Reputation: 5444
I am trying to update a ListBox
with a large amount of data in a way that keeps the user interface (UI) responsive.
To do this, I am using the following code to collect the data into batches of 100 items, and then insert these batches into the ListBox
in one go, rather than inserting each item individually. This should prevent the UI from being updated each time an item is added, but unfortunately, the code does not work as expected and the UI is only updated after all of the items have been added to the ListBox
.
public partial class Form1 : Form
{
private SynchronizationContext synchronizationContext;
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
synchronizationContext = SynchronizationContext.Current;
await Task.Run(() =>
{
ConcurrentDictionary<int, int> batch = new ConcurrentDictionary<int, int>();
int count = 0;
for (var i = 0; i <= 10000; i++)
{
batch[i] = i;
count++;
if (count == 100)
{
count = 0;
UpdateUI(batch);
batch = new ConcurrentDictionary<int, int>();
}
}
});
}
private void UpdateUI(ConcurrentDictionary<int, int> items)
{
synchronizationContext.Post(o =>
{
listBox1.SuspendLayout();
foreach (var item in items)
{
listBox1.Items.Add(item.Value);
}
listBox1.ResumeLayout();
}, null);
}
}
Upvotes: 1
Views: 306
Reputation: 43475
You don't need a multithreading approach in order to update the UI. All you need is to suspend the painting of the ListBox
during the mass insert, by using the ListBox.BeginUpdate
and ListBox.EndUpdate
methods:
private void button1_Click(object sender, EventArgs e)
{
listBox1.BeginUpdate();
for (var i = 1; i <= 10000; i++)
{
listBox1.Items.Add(i);
}
listBox1.EndUpdate();
}
The Control.SuspendLayout
and Control.ResumeLayout
methods are used when you add controls dynamically in a flexible container, and you want to prevent the controls from jumping around when each new control is added.
Upvotes: 1