我想从窗体中的BackgroundWorker获取控件的属性:
foreach (ListViewItem i in ListView.CheckedItems) { //error: Cross-thread operation not valid: Control 'ListView' accessed from a thread other than the thread it was created on.
//do something with i
}有谁能建议最简单和最容易的方法来做这件事吗?
发布于 2012-05-13 21:12:03
让我再试一次...
1.)将ListView拖到窗体上
2.)将BackgroundWorker拖到窗体上
3.)创建一个遍历ListViewItem集合的方法
private void LoopThroughListItems()
{
foreach (ListViewItem i in listView1.CheckedItems)
DoSomething();
}4.)添加代码以在BackgroundWorker的DoWork事件内调用LoopThroughListItems()
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
LoopThroughListItems();
}5.)在表单中,加载-在主线程上执行代码(可以工作),然后在backgroundWorkder线程上执行代码(失败)
private void Form1_Load(object sender, EventArgs e)
{
// Try it on the UI Thread - It works
LoopThroughListItems();
// Try it on a Background Thread - It fails
backgroundWorker1.RunWorkerAsync();
}6.)修改代码以使用IsInvokeRequired/Invoke
private void LoopThroughListItems()
{
// InvokeRequired == True when executed by non-UI thread
if (listView1.InvokeRequired)
{
// This will re-call LoopThroughListItems - on the UI Thread
listView1.Invoke(new Action(LoopThroughListItems));
return;
}
foreach (ListViewItem i in listView1.CheckedItems)
DoSomething();
}7.)再次运行应用程序-现在它可以在UI线程和非UI线程上运行。
这就解决了问题。检查IsInvokeRequired/Invoking是一种常见的模式,您会经常使用它(这就是为什么它包含在所有控件中)。如果你到处都在做这件事,你可以做一些聪明的事情,然后把它都包装起来--就像这里描述的那样:Automating the InvokeRequired code pattern
发布于 2012-05-16 04:51:45
尝试如下所示:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void OnClick(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void OnDoWork(object sender, DoWorkEventArgs e)
{
foreach (ListViewItem i in GetItems(listView1))
{
DoSomething(i);
}
}
private IEnumerable<ListViewItem> GetItems(ListView listView)
{
if (InvokeRequired)
{
var func = new Func<ListView, IEnumerable<ListViewItem>>(GetItems);
return (IEnumerable<ListViewItem>)Invoke(func, new[] { listView });
}
// Create a defensive copy to avoid iterating outsite UI thread
return listView.CheckedItems.OfType<ListViewItem>().ToList();
}
private void DoSomething(ListViewItem item)
{
if (InvokeRequired)
{
var action = new Action<ListViewItem>(DoSomething);
Invoke(action, new[] { item });
return;
}
// Do whatever you want with i
item.Checked = false;
}
}
}然而,你的问题真的很笼统。如果你分享更多的细节,也许会有一个更容易或更好的解决方案。
https://stackoverflow.com/questions/10571949
复制相似问题