2017-08-14 81 views
-1

我想使用BackgroundWorker来为我收集一些数据,并在我的窗体中更新ListView,同时我显示一个进度条并允许gui不被冻结。 当我尝试使用BackgroundWorker更新我的ListView时,出现跨线程错误。为了克服这个问题,我在BackgroundWorker中填充一个临时ListView,并将其分配给结果,然后使用来自backgroundWorker1_RunWorkerCompleted的填充来填充我的原始ListView。如何正确使用BackgroundWorker更新ListView? [c#.NET 3.5]

#1:有没有一种更优雅的方式来更新/显示我的ListView,而无需在_RunWorkerCompleted中创建另一个临时ListView?

#2:有没有办法将原始listview作为参数传递给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()); 
     } 
} 

回答

1

要更新跨线程的用户界面,你需要调用一个新的 代表。检查调用此此链接的信息: Invoke

是的,你可以做,在一个优雅的方式,而不需要其他临时的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); 
     } 
    } 
} 
+1

也许可以解释一下调用调用。这里有一个相关的[链接](https://msdn.microsoft.com/en-us/library/zyzhdc6b(v = vs.110).aspx)。 –

+1

感谢您的快速反应和描述链接!我可以确认这种方法对我有用 – AlkiZaganiaris

-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); })); 
     } 
    } 
} 
+0

为什么我的排名降低,而另一个排名却是一个非常相似的答案,但代码更多? –

+0

我没有投票,但我最好的猜测是你说你需要锁定资源,但没有解释为什么。据我的理解,锁定它不是必要的,但我肯定是错的,在线程方面,我并不专业。 –

+0

感谢您的快速响应!不知道为什么它排名下来.. @ st3_121 – AlkiZaganiaris