grmihel grmihel - 2 months ago 12
C# Question

Populate ListBox with a IEnumrable on another thread (winforms)

I'm wondering what would be the best way to populate a ListBox control of a WinForm, populated depending on a radio btn?

I have seen some suggestions to use a foreach to loop over each object of my list, and Add() them to the listBox.items.Add(), but this seems to be a really bad idea, since the list from rabio btn 1 returns a list with 10.000 records (takes quiet some time to loop over, and the UI freeze while looping, bad bad idea).

Is there any better way to do this, and maybe in a seperated Task to stop UI freeze??

private void PopulateListBox()
{
foreach (var item in Controller.ReturnBigResultSet())
this.Invoke((MethodInvoker)(() => listBox1.Items.Add(item)));
}


UPDATE: Code block using AddRange:

var watch = new Stopwatch();
watch.Start();
var list = Controller.GetAllEntries().ToArray();
Debug.WriteLine("List returned in {0}s with a size of {1}", watch.Elapsed.TotalSeconds, list.Count<Lejlighed>());
watch.Restart();
listBox1.Items.AddRange(list);
watch.Stop();
Debug.WriteLine("Added {0} items in {1}s", listBox1.Items.Count, watch.Elapsed.TotalSeconds);


Output is:

List returned in 3.8596527s with a size of 19022
Added 19022 items in 1.9223412s

Answer

You don't need to populate the ListBox from in another thread. If you use a correct way to populate it, populating 10000 items takes a short time (for me 200-300 ms).

The part that you may want to put in another thread is loading data not adding data to ListBox.

To add items to ListBox it's enough to use AddRange:

this.listBox1.AddRange(array);

Which is equivalent to using below code. First call BeginUpdate method of ListBox and then use a loop to Add items to Items collection and at last call EndUpdate:

this.listBox1.BeginUpdate();
foreach (var item in array)
{
    this.listBox1.Items.Add(item);
}
this.listBox1.EndUpdate();

Take a look at source code of AddRange method.

Comments