如何正确使用BackgroundWorker更新ListView? [c#.NET 3.5]
How to correctly use BackgroundWorker to update ListView? [c# .NET 3.5]
我正在尝试使用 BackgroundWorker 为我收集一些数据并更新表单中的 ListView,同时显示进度条并允许不冻结 gui。
当我尝试使用 BackgroundWorker 更新我的 ListView 时出现跨线程错误。为了克服这个问题,我在 BackgroundWorker 中填充了一个临时 ListView 并将其分配给结果,然后使用 backgroundWorker1_RunWorkerCompleted 中的它来填充我的原始 ListView。
#1: 有没有更优雅的方法 update/display 我的 ListView 而不必在 _RunWorkerCompleted 中创建另一个临时 ListView?
#2: 有没有办法将原始列表视图作为参数传递给 backgroundWorker?
我感谢对此的任何反馈。
提前致谢!
伪代码
// 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());
}
}
To update user interface in cross-thread, you need to Invoke a new
Delegate. Check this link here for information on Invoke:
Invoke
是的,你可以用一种优雅的方式做到这一点,而不需要另一个临时列表视图:
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);
}
}
}
您可能只需要在线程访问资源时锁定资源。
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); }));
}
}
}
我正在尝试使用 BackgroundWorker 为我收集一些数据并更新表单中的 ListView,同时显示进度条并允许不冻结 gui。 当我尝试使用 BackgroundWorker 更新我的 ListView 时出现跨线程错误。为了克服这个问题,我在 BackgroundWorker 中填充了一个临时 ListView 并将其分配给结果,然后使用 backgroundWorker1_RunWorkerCompleted 中的它来填充我的原始 ListView。
#1: 有没有更优雅的方法 update/display 我的 ListView 而不必在 _RunWorkerCompleted 中创建另一个临时 ListView?
#2: 有没有办法将原始列表视图作为参数传递给 backgroundWorker?
我感谢对此的任何反馈。
提前致谢!
伪代码
// 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());
}
}
To update user interface in cross-thread, you need to Invoke a new Delegate. Check this link here for information on Invoke: Invoke
是的,你可以用一种优雅的方式做到这一点,而不需要另一个临时列表视图:
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);
}
}
}
您可能只需要在线程访问资源时锁定资源。
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); }));
}
}
}