3

...或者...

“我唤醒了 WPF 深处的什么邪恶?”

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

  • 创建一个画布对象
  • 创建一个新的 NameScope 对象
  • 将该 NameScope 分配给 Canvas
  • 在画布上画出我想要的任何东西
  • 使用 Canvas 的大小调用 canvas.Measure()
  • 使用 Canvas 的可用矩形调用 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 的情况下重写这个处理代码,我也宁愿避免这种情况。
4

2 回答 2

2

您的后台线程使用什么公寓模型?

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

更新:

如果 STA 线程不是问题,那么我会尝试将您的画布绘制成块。基本上,如果您执行以下操作:

Dispatcher.BeginInvoke(...)

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

更新 2:

您还可以尝试使用 .NET 框架参考源调试 Canvas 对象的源代码。您可以通过在工具->选项下的调试选项中打开“启用 .net 框架源步进”来启用此功能。

于 2009-04-29T17:15:46.583 回答
-1

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

于 2009-04-29T17:42:10.623 回答