我正在尝试使用BackgroundWorker为我收集一些数据并在我的表单中更新ListView,同时显示进度条并允许gui不被冻结。 当我尝试使用BackgroundWorker更新我的ListView时,我收到了一个跨线程错误。为了解决这个问题,我在BackgroundWorker中填充临时ListView并将其分配给结果,然后使用 backgroundWorker1_RunWorkerCompleted 中的那个来填充我原来的ListView。
#1:是否有一种更优雅的方式来更新/显示我的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());
}
}
答案 0 :(得分:1)
要在跨线程中更新用户界面,您需要调用新的 代表。有关调用的信息,请在此处查看此链接: 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);
}
}
}
答案 1 :(得分:-1)
您可能只需要在线程访问时锁定资源。
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); }));
}
}
}