WPF Canvas:Children.Add()挂在后台线程上?

时间:2009-04-29 17:08:12

标签: wpf multithreading canvas

...或...

“我醒来的WPF深处有什么邪恶?”

我正在后台线程上创建一个Canvas并将其渲染为位图。我已经在生产代码中工作了一年多,现在没有问题。我做了以下事情:

  • 创建Canvas对象
  • 创建一个新的NameScope对象
  • 将NameScope指定给画布
  • 在画布上绘制我想要的任何东西
  • 使用Canvas的大小调用canvas.Measure()
  • 使用Canvas的可用rect
  • 调用canvas.Arrage()
  • 调用canvas.UpdateLayout()
  • 渲染画布

在绘制步骤中,我总是调用canvas.Children.Add()将UIElements放到Canvas上。这一直有效。

现在,由于一些莫名其妙的原因,在我正在处理的应用程序中的一个特定情况下,对canvas.Children.Add()的调用不确定地挂起,阻塞了我的后台线程。我想不出有任何关于已经工作了一年多的代码和这个具体案例的不同之处。

有人可以提出为什么调用canvas.Children.Add()会像这样挂起的可能原因吗?

编辑:后台线程是一个STA线程(后台线程处理模型已经到位,因为我无法在MTA线程上使用WPF处理图像),所以线程公寓模型不应该不是罪魁祸首。

编辑#2 :虽然我理解为什么人们建议我从我的后台线程尝试Dispatcher.BeginInvoke(),但我不喜欢这个选项有两个原因:

  1. 我希望我的后台线程处理在该线程上是同步的。我的后台线程有一个队列,其他线程提交图像作业,我的后台线程处理每个作业。使用Dispatcher.BeginInvoke()增加了我宁愿避免的另一层复杂性。
  2. 到目前为止,我从未 需要 。在我的后台线程上同步执行此后台处理只是简单的工作。我试图确定这个奇怪的边缘情况可能会有什么不同,导致此代码不起作用。如果我不能让它工作,我最终会在没有WPF的情况下重写这个处理代码,我也宁愿避免使用。

2 个答案:

答案 0 :(得分:2)

您使用哪种公寓模型作为后台主题?

我相信WPF需要在STA线程上运行。当您生成后台线程时,请尝试将其设置为STA的公寓。

<强>更新

如果STA线程不是问题,那么我会尝试将画布绘制成块。基本上如果你做了:

Dispatcher.BeginInvoke(...)

从您的线程

,提供的委托被推送到调度程序队列的后面,允许其他排队的任务执行。

更新2:

您还可以尝试使用.NET框架参考源调试Canvas对象的源代码。您可以通过在Tools-&gt; Options下的调试选项中启用“enable .net framework source stepping”来启用此功能。

答案 1 :(得分:-1)

尝试在后台线程中调用Dispatcher.Run()。