多线程环境问题

时间:2013-10-11 15:51:48

标签: c# wpf multithreading

我有一个WPF控件正在我的应用程序的主线程中处理,渲染和显示。控件将数千个数据点上传到名为“Layer”的对象中。以下是对象/类层次结构的粗略描述:

public class WPFControl{

   private List<Layer> myLayers;

   public List<Layer> MyLayers{
      get{ return myLayer;}
   }       

   ...
}

public class Layer{
   private List<DataPoint> myDataPoints;

   public List<DataPoint> MyDataPoints{
        get{ return myDataPoints;}
   }

   ...
}

public class DataPoint{
   ....
}

由于这个“Layer”对象的创建过程需要一些时间,因为它必须读取和上传数千个DataPoint,因此我在另一个线程中创建该层对象。这很好用,很好地返回Layer对象。问题是,当我尝试将其添加到WPF控件时,显示如下:

myWpfControl.MyLayers.Add(layerCreatedInOtherThread);

WPF控件触发此错误:

The calling thread cannot access this object because a different thread owns it

我想,好吧,我可以像这样使用调度员:

myWpfControl.Dispatcher.Invoke((Action)
 (()=>{                                   
    myWpfControl.MyLayers.Add(layerCreatedInOtherThread);
 })
 );

但我一直得到同样的错误。我有什么想法可以解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

使用BackgroundWorker,您可以在另一个线程上运行任务,然后在完成后可以访问UI线程中的结果。

private System.ComponentModel.BackgroundWorker bgWorker;
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);

 //Start the work
 bgWorker.RunWorkerAsync(null) //you can send an argument instead of null

做好工作

    private void backgroundWorker1_DoWork(object sender, 
        DoWorkEventArgs e)
    {   
        // Get the BackgroundWorker that raised this event.
        BackgroundWorker worker = sender as BackgroundWorker;

        // Assign the result of the computation 
        // to the Result property of the DoWorkEventArgs 
        // object. This is will be available to the  
        // RunWorkerCompleted eventhandler.
        e.Result = CreateLayerInOtherThread(); //if you sent an arg instead of null it as availalbe in e.Argument and can be cast from object.
    }

完成后获得结果。这在UI线程上运行,因此您可以更新它。

    private void bgWorker_RunWorkerCompleted(
        object sender, RunWorkerCompletedEventArgs e)
    {
        // First, handle the case where an exception was thrown. 
        if (e.Error != null)
        {
            MessageBox.Show(e.Error.Message);
        }
        else if (e.Cancelled)
        {
            // Next, handle the case where the user canceled  
            // the operation. 
            // Note that due to a race condition in  
            // the DoWork event handler, the Cancelled 
            // flag may not have been set, even though 
            // CancelAsync was called.


        }
        else
        {
            // Finally, handle the case where the operation  
            // succeeded.
            Layer myLayer = (Layer)e.Result;
            myWpfControl.MyLayers.Add(myLayer);
        }


    }