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

WPF: Exception if new EllipseGeometry() called on non UI thread

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

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更新如下,在canvas上画了一个圆圈:

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);
  });
}

我不明白的是,为什么在 Dispatcher 之前调用 var cirkel = new EllipsGeometry()... 会抛出异常。 在调度员之前创建cirkel的中心点对象没有问题。 Ellipse 对象有何不同?

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

我还将动作添加到动作集合中。 我是否应该研究使用 Observable 集合和 Notify 事件来在 canvas 上绘制 cirkel?

How is the EllipseGeometry object different?

它是一个 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);
});