伪代码:
form1
{
int i;
label1;
Add()
{
i++;
label1 = i.ToString(); //#ErrorLine
}
backgroundworker worker;
worker_DoWork()
{
FileGuard guard = new FileGuard();
guard.FileKilled += guard.KillH(Add);
guard.StarGuarding(); //there is system watcher inside
//this guard and some processing code
//that will fire event FileKilled();
}
}
调用StartGuarding()工作程序将得到补充 但是当事件FileKill被触发时,我在#ErrorLine
行上发现了这个错误跨线程操作无效:控制'form1'从其创建的线程以外的线程访问。
答案 0 :(得分:4)
这与事件本身无关,而是与另一个线程访问UI控件的事实有关。在Windows窗体中,不允许从主UI线程以外的任何其他线程与UI进行交互。
您可以使用InvokeRequired
检查您是否在无法访问UI的线程上,然后使用Invoke
在UI线程上运行代码(如果需要)。它可能看起来像这样:
private void DoStuffWithGUI()
{
if (InvokeRequired)
{
Action work = DoStuffWithGUI;
Invoke(work);
}
else
{
// Your normal logic
}
}
您可以直接从ProgressChanged和RunWorkerCompletedEvents使用UI(因为它们会自动编组到UI线程)。但是你在DoWork中所做的所有工作(以及因此你可能在工作中提出的所有事件)都在一个单独的线程中运行,并且必须使用Invoke编组到UI线程。来自MSDN的BackgroundWorker:
你必须小心不要操纵 你的任何用户界面对象 DoWork事件处理程序。代替, 与用户界面进行通信 通过ProgressChanged和 RunWorkerCompleted事件。
答案 1 :(得分:2)
这是因为当系统调用FileKilled时会使用第三个线程。
对于BackgroundWorker
,您应该使用事件来处理GUI更新:http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
答案 2 :(得分:0)
您无法从其创建的表单以外的任何内容访问Windows窗体或WPF对象,因此您的问题。
使用调度程序将更新发送回UI线程。
如果您可以详细说明您是使用WinForms还是WPF,我们可以提供更多信息。
答案 3 :(得分:0)
您无法更改从创建它们之外的线程修改控件。您需要使用InvokeRequired属性和Invoke方法来编组来自后台线程的UI线程调用。
private readonly _lockObject = new Object();
Add()
{
lock(_lockObject)
{
i++;
if(label1.InvokeRequired)
Invoke(new Action( () => label1 = i.ToString()));
else
label1 = i.ToString();
}
}
请注意,lock
不是必须避免此异常的。它添加了使方法线程安全。