2008-12-15 17 views
6

Je souhaite que mon agent d'arrière-plan ajoute des éléments à une zone de liste, il semble le faire lors du débogage, mais la liste ne montre pas les valeurs. Je soupçonne que cela a quelque chose à voir avec l'ajout d'éléments à l'intérieur du thread de travail d'arrière-plan, dois-je les ajouter à un tableau, puis remplir la zone de liste à partir du tableau pendant backgroundWorker1_RunWorkerCompleted?C# Puis-je ajouter des valeurs à une liste avec un fil d'arrière-plan?

Merci pour l'aide.

Répondre

1

Vous pouvez les ajouter pendant un fil d'arrière-plan via:

Form.Invoke 

ou

Form.BeginInvoke 

qui sont nécessaires pour marshall l'appel d'un fil d'arrière-plan à un thread d'interface utilisateur principale. Cependant, je suis sûr que BackgroundWorker propose un événement qui est automatiquement appelé sur le fil de premier plan et vous devriez être en mesure de mettre à jour cet événement sans aucun problème. Ceci est "ProgressChanged" qui peut être déclenché par le processus de travail en arrière-plan en appelant ReportProgress.

Avez-vous déjà essayé d'appeler .Refresh() dans la liste?

6

Vous pouvez, mais vous devez informer votre arrière-plan d'état de rapport, et envoyer l'entrée pour la boîte avec l'état actuel à cet événement. Dans la méthode pour cet événement, vous pouvez accéder à la boîte et mettre la nouvelle valeur.

Sinon, vous devez appeler manuellement.

public Form1() 
     { 
      InitializeComponent(); 

      BackgroundWorker bw = new BackgroundWorker(); 
      bw.WorkerReportsProgress = true; 
      bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); 
      bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
      bw.RunWorkerAsync(); 
     } 

     void bw_DoWork(object sender, DoWorkEventArgs e) 
     { 
      for (int i = 0; i < 10; i++) 
      { 
       ((BackgroundWorker)sender).ReportProgress(0, i.ToString()); 
      } 
     } 

     void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      listBox1.Items.Add((string)e.UserState); 
     } 
+0

Un inconvénient de ce procédé (ajout d'éléments, un par un) serait que l'on ne peut pas joindre population listbox à l'intérieur BeginUpdate/EndUpdate. –

+0

J'ajoute 500k articles à la listbox, mais c'est toujours l'interface utilisateur qui bloque le composant bw. des idées pourquoi? – Smith

+0

Dans ce cas, je vous recommande de ne pas ajouter les éléments un par un, mais peut-être signaler la progression seulement tous les 100 ou 1000 itérations avec un tas d'éléments à ajouter. L'événement ProgressChanged doit être appelé dans le thread principal, donc l'appeler gèle souvent le gui. –

0
+0

Ce n'est pas très utile, car il faut d'abord lire tout le fil. –

+0

Est-ce vraiment un problème pour vous! Ceci est juste un lien utile à une discussion similaire. Toutes les réponses sont utiles pour acquérir une meilleure compréhension et le fil n'est pas long. – paul

13

Vous pouvez utiliser Invoke comme ceci:

private void AddToListBox(object oo) 
{ 
    Invoke(new MethodInvoker(
        delegate { listBox.Items.Add(oo); } 
        )); 
} 
+0

Oui, mais BackgroundWorker le fait automatiquement avec l'événement. –

+0

Je sais, je ne propose qu'une alternative;) –

+0

Les alternatives sont toujours bonnes, le sentiment d'avoir un choix est essentiel pour la matrice ;-) –

1

-je ajouter des fonctions comme suit afin que je puisse ajouter des éléments à la zone de liste soit à partir des principaux sujets de discussion ou de fond. Ce thread vérifie si un appel est nécessaire et utilise Invoke si nécessaire.

delegate void AddListItemDelegate(string name,object otherInfoNeeded); 

    private void 
    AddListItem(
     string name, 
     object otherInfoNeeded 
    ) 
    { 
    if (InvokeRequired) 
    { 
     BeginInvoke(new AddListItemDelegate(AddListItem), name, otherInfoNeeded 
     return; 
    } 

    ... add code to create list box item and insert in list here ... 
    } 
0

Application.Doevents() fonction résoudra le problème.

1

si vous essayez de mettre à jour une base de données. Dans une liste, je suggère de créer un ensemble de données. Par exemple, si vous faites quelque chose pour chaque élément d'une base de données. Copiez le jeu de données de base de données en créant un nouveau jeu de données et en le déclarant par mainDataset.

par exemple: // l'ensemble de données est gridview DataSet1

BackgroundWorker_DoWork(object sender, DoWorkArgs e) 
{ 
    Dataset dataset2 = dataset1; 
    foreach(DataGridViewRow row in GridView) 
    { 
     //do some work 
     dataset2.Main.AddMainRow(values to add); 
     dataset2.AcceptChanges(); 
    } 
} 


BackgroundWorker_WorkCompleted(object sender, DoWorkArgs e) 
{ 
    //Forces UI thread to valitdate dataset 
    dataset2.update(); 

    // Sets file Path 
    string FilePath = "Some Path to file"; 

    dataset2.writexml(FilePath, XmlWriteOptions.WriteSchema); 

    //if you use xml to fill your dataset filepath to write should equal path to dataset1 xml 
    dataset1.Refresh(); 
}