WPF:如果在非UI线程上调用新的EllipseGeometry(),则异常

时间:2017-05-11 08:30:39

标签: wpf multithreading canvas dispatcher pathgeometry

我有一个WPF应用程序,它从EasyNetQ / RabbitMQ消息队列中检索对象“移动”消息。正如我在记录器中看到的那样,使消息正常工作。

private void btnSubscribeToMessageQ_Click(object sender, RoutedEventArgs e)
{
  _logger.Debug("Listening for messages.");
  _messageBus.Subscribe<RZMD.Messages.Movement>("test", HandleMovement);
}

处理消息的步骤如下:

private void HandleMovement(RZMD.Messages.Movement movementMessage)
{
  _logger.Debug("Movement: {0}", movementMessage);
  AddCirkelToCanvasWithDispatcher(movementMessage);
  _movements.Add(movementMessage);
}

通过在画布上绘制圆圈来更新UI:

private void AddCirkelToCanvasWithDispatcher(RZMD.Messages.Movement movementMessage)
{
  var center = new Point(movementMessage.X, movementMessage.Y);
  //var cirkel = new EllipseGeometry() { Center = center, RadiusX = 5, RadiusY = 5 }; << 
  // above line causes exception re threads
  // System.InvalidOperationException: 'The calling thread cannot access 
  // this object because a different thread owns it.'

  Application.Current.Dispatcher.Invoke( ()=>
  {
    //if I put new EllipseGeometry() here all is fine
    var cirkel = new EllipseGeometry() { Center = center, RadiusX = 5, RadiusY = 5 };
    var path = new Path() { Stroke = Brushes.Black, Data = cirkel };
    cnvFloor.Children.Add(path);
  });
}

我不明白为什么对var cirkel = new EllipsGeometry()...的调用在Dispatcher之前放置时会引发异常。 在调度程序之前创建cirkel的中心Point对象没有问题。 Ellipse对象有何不同?

这是正确的(现代)方法吗?或者是否有更好的工具,如'async / await','TPL'或'Parallel Linq'

此外,我正在将动作添加到一系列动作中。 我应该调查使用Observable集合和Notify事件来在画布上绘制圆圈吗?

1 个答案:

答案 0 :(得分:2)

  

EllipseGeometry对象有何不同?

它是System.Windows.Threading.DispatcherObject,因此具有线程关联性,即除非它被冻结,否则只能在创建它的线程中访问它。

您可以冻结它以使其跨线程可访问,而不是在Dispatcher操作中创建EllipseGeometry:

var cirkel = new EllipseGeometry() { Center = center, RadiusX = 5, RadiusY = 5 };
cirkel.Freeze();

Application.Current.Dispatcher.Invoke(() =>
{
    var path = new Path() { Stroke = Brushes.Black, Data = cirkel };
    cnvFloor.Children.Add(path);
});