Task.Factory和线程之间的通信

时间:2012-03-12 10:23:44

标签: c# wpf multithreading task-parallel-library

我有一个在wpf中生成GUI元素的线程。画布用于绘制对象(矩形等等......)

这个 wpf线程调用另一个线程,我们将其命名为计算线程。该线程计算要在画布中显示的元素的大小和位置等。

我想让这两个部分(GUI和计算)在不同的线程中运行。 “计算线程”基于库而不引用wpf功能。

现在我想显示wpf线程显示的计算线程的中间数据。 我这样做:

calc-thread触发由wpf-thread实现的事件(DataReady):

void MyRegStringObject_DataReady()
{
  if (DebugMode)
    MyDrawingBoard.DrawRegElements();
}

现在的问题是,抛出一个错误:“调用线程无法访问此对象,因为另一个线程拥有它”

在stackoverflow中有一些回答的问题引用了这个错误,但在我的情况下,它们都没有帮助。

DrawRegElements()函数想要清除画布对象(以及其他内容):

curCanvas.Children.Clear();

在代码中的这个位置抛出错误。 看来,来自calc-thread的事件触发的函数MyRegStringObject_DataReady也由calc-thread承担。但是在类中定义了wpf-thread基于。

我该如何解决这个问题?有谁有想法吗? 顺便说说: calc方法以这种方式调用:

CalcElements = Task.Factory.StartNew<bool>(MyRegStringObject.CalcRegElements);

线程完成后我定义了:

CalcElements.ContinueWith((FinishCalcRegElements) =>
{
  MyDrawingBoard.DrawRegElements();
}, CancellationToken.None, TaskContinuationOptions.None, 
TaskScheduler.FromCurrentSynchronizationContext());

没问题。 Everythins运行完美。 ContinueWith中定义的函数似乎是由wpf-thread所有。

1 个答案:

答案 0 :(得分:2)

错误消息很简单,您正在尝试从现在拥有的线程访问UI元素。将此工作委托给与主UI线程关联的WPF Dispatcher,它将所有消息从工作线程发布到UI线程:

Application.Current.Dispatcher.BeginInvoke((ThreadStart)delegate
   {            
       MyDrawingBoard.DrawRegElements();   
   });

为了确保您使用与主UI线程关联的正确Dispatcher,您可以将其作为参数传递给工作线程代码,因此只需从主UI线程传递Dispatcher.Current,否则调用{{工作线程中的1}}将初始化与调用工作线程关联的新实例。或者只使用引用主UI线程的Dispatcher的Dispatcher.CurrentDispatcher

PS:

  

但是在类中定义了wpf-thread基于

这是错误的假设,类本身与任何线程无关。 Concrtete类实例是。因此,您可以在UI或工作线程中创建UI /非UI相关类。

线程Application.Current.Dispatcher事件被触发的重要一点是什么?