我有一个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事件来在画布上绘制圆圈吗?
答案 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);
});