如何正确使用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); }));
        }
     }
}