背景工人事件

时间:2011-01-02 10:54:45

标签: c# .net multithreading event-handling backgroundworker

伪代码:

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'从其创建的线程以外的线程访问。

4 个答案:

答案 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不是必须避免此异常的。它添加了使方法线程安全。