检测到交叉线程操作?

时间:2014-09-08 10:51:19

标签: c# multithreading winforms backgroundworker

我正在处理使用BackgroundWorker Thread的应用程序。我有一个按钮点击事件,我正在做一些事情

 btnLocate_Click(Object sender, EventArgs e)
 {
    BackgroundWorker bw = new BackgroundWorker();
    bw.DoWork += bw_DoWork;
    bw.RunWorkerCompleted += bw_RunWorkerCompleted;
    bw.RunWorkerAsync(lstNumbers.CheckedItems[0].ToString());
 }

在Background Worker do work事件中,我在全局定义的ObservableCollection中添加了一些像这样的值

private void bw_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {
        lock (locker)
        {
            _RecData.Add(new RecNumberData
                    {
                        // Some Values 
                    });
         }
    }

在BackgroundWorker完成事件中,我将此集合设置为网格的数据源,并启动创建新BackgroundWorker的计时器并再次执行相同的工作。

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{  
    grid.DataSource = RecData;
    timer1.Start();
}

private void timer1_Tick(object sender, EventArgs e)
{
    timer1.Stop();
    BackgroundWorker bw = new BackgroundWorker();
    bw.DoWork += bw_DoWork;
    bw.RunWorkerCompleted += bw_RunWorkerCompleted;
    bw.RunWorkerAsync(lstNumbers.CheckedItems[0].ToString());
}

现在,第一次BackgroundWorker运行时代码运行正常。但是当第二次在Timer滴答事件之后运行时,异常在Cross Thread Opeartion Detected行引发。

_RecData.Add(new RecNumberData
    {
        // Some Values 
    });

可能是什么原因?

3 个答案:

答案 0 :(得分:3)

没有看到更多代码的猜测,但我怀疑:

  • 第一次向集合中添加值时,集合未绑定到UI =>没问题

  • 第二次通过它绑定到UI(在第一个完整的事件中),因此您的后台工作者正在尝试更新UI。

解决方案可能是为您的第二个BackgroundWorker创建第二个可观察集合。或者推迟将结果添加到集合中,直到完成事件。

答案 1 :(得分:2)

您正在从GUI线程外部修改GUI对象。你不应该这样做。

通过将RecData设置为GUI对象的数据源,对RecData的每次更改都将触发将更改GUI对象的通知。绑定RecData后,您正在从后台工作线程更改RecData,从而更改您的GUI对象。数据绑定到GUI对象的对象不得被GUI线程以外的任何线程修改。

您可以使用Control.BeginInvoke在GUI线程上排队操作。

答案 2 :(得分:0)

您正在将数据添加到用作图形组件(网格)的数据源的变量中,您需要告诉我们您正在使用的UI技术(WPF?WInform?)。

正在发生的事情是你在一个不是运行UI的线程上做某事,并且大多数UI技术不允许影响它们的事情在另一个线程上运行,有一些机制可以解决这个问题但是它们取决于技术。

大多数情况下,您需要注册更改UI读取的数据的代码以在调度程序上运行(一旦可用,它将排队并在主线程上运行)