Reputation: 13
I am trying to use a BackgroundWorker to gather some data for me and update a ListView in my form while i display a progress bar and allow for the gui to not be frozen. I am getting a cross-thread error when i try to update my ListView using the BackgroundWorker. To overcome this, i populate a temporary ListView in the BackgroundWorker and assign it to the result and then use that from the backgroundWorker1_RunWorkerCompleted to populate my original ListView.
#1: Is there a more elegant way to update/display my ListView without having to create another temporary ListView in the _RunWorkerCompleted?
#2: Is there a way to pass the original listview as an argument to the backgroundWorker?
I appreciate any feedback on this.
Thanks in advance!
Pseudo-Code
// Original ListView in Form
ListView orginalListView = new ListView();
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
ListView backgroundList = new ListView();
foreach(var data in database)
{
listViewItem = data.value;
backgroundList.Items.Add(listViewItem);
}
e.Result = backgroundList;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Can I avoid needing to create a temp LV ??
ListView tempLV = new ListView();
tempLV = (ListView)e.Result;
foreach (ListViewItem item in tempLV.Items)
{
orginalListView .Items.Add((ListViewItem)item.Clone());
}
}
Upvotes: 0
Views: 2489
Reputation: 34673
To update user interface in cross-thread, you need to Invoke a new Delegate. Check this link here for information on Invoke: Invoke
Yes you can do that in an elegant way without the need of another temporary listview:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
foreach (var data in database)
{
if (orginalListView.InvokeRequired)
{
orginalListView.Invoke(new MethodInvoker(delegate
{
listViewItem = data.value;
orginalListView.Items.Add(listViewItem);
}));
}
else
{
listViewItem = data.value;
orginalListView.Items.Add(listViewItem);
}
}
}
Upvotes: 2
Reputation: 32
You will likely just need to lock the resource whilst the thread is accessing it.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
foreach(var data in database)
{
listViewItem = data.value;
String name = "orginalListView";
lock (((ListView)this.Controls[name]))
{
//Update UI, invoked because on different thread.
Invoke(new MethodInvoker(delegate { ((ListView)this.Controls[name]).Items.Add(listViewItem); }));
}
}
}
Upvotes: -1