6

I want my background worker to add items to a list box, it appears to do so when debugging but the listbox doesn't show the values. I suspect this is something to do with adding items whilst inside the background worker thread, do I need to add these to an array and then populate the list box from the array during backgroundWorker1_RunWorkerCompleted?

Thanks for the help.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880

6 Answers6

14

You can use Invoke like this:

private void AddToListBox(object oo)
{
    Invoke(new MethodInvoker(
                   delegate { listBox.Items.Add(oo); }
                   ));
}
Gonzalo Quero
  • 3,303
  • 18
  • 23
6

You can, but you must advise your Backgroundworker to report state, and send the input for the box with the current state to that event. In the method for that event, you can access the box and put the new value in.

Otherwise you need to invoke manually.

 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);
        }
Oliver Friedrich
  • 9,018
  • 9
  • 42
  • 48
  • A drawback of this method (adding items one by one) would be that one cannot enclose listbox population within BeginUpdate/EndUpdate. – Sorin Comanescu Nov 12 '09 at 10:55
  • am adding 500k items to the listbox, but its still freezing th UI the bw component is. any ideas why? – Smith Feb 16 '11 at 16:45
  • In that case i'd recommend you to not add the items one by one, but maybe report the progress only all 100 or 1000 iterations with a bunch of items to add. The ProgressChanged-Event needs to be invoked into the main guy thread, so calling it to often freezes the gui. – Oliver Friedrich Feb 17 '11 at 09:34
1

You can add them while on a background thread via:

Form.Invoke

or

Form.BeginInvoke

which are required to marshall the call from a background thread to a main UI thread. However I'm pretty sure BackgroundWorker offers an event that automatically gets called on the Foreground thread and you should be able to update on this event without any problems. This is "ProgressChanged" which can be fired by the background worker process by calling ReportProgress.

Have you tried calling .Refresh() on the listbox as well?

sth
  • 222,467
  • 53
  • 283
  • 367
Quibblesome
  • 25,225
  • 10
  • 61
  • 100
1

I add functions like the following so that I can add items to the list box from either the main thread or background threads. Thi thread checks if a Invoke is necessary and then uses Invoke if it is necessary.

  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 ...
  }
Marcus Erickson
  • 1,561
  • 1
  • 11
  • 10
1

if you are trying to update a database. From a listbox i would suggest creating a dataset.

for instance, if your doing something for each item in a database. Copy the database dataset, by creating new dataset and declaring by mainDataset.

for example: // the gridview dataset is 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();
}
Michael Smith
  • 77
  • 1
  • 10
0

Application.Doevents() function will solve the problem.

Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453