【问题标题】:WPF Canvas: Children.Add() hanging on background thread?WPF Canvas:Children.Add() 挂在后台线程上?
【发布时间】:2009-04-29 17:08:11
【问题描述】:

...或...

“我唤醒了 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 的情况下重写这个处理代码,我也宁愿避免这样做。

【问题讨论】:

    标签: wpf multithreading canvas


    【解决方案1】:

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

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

    更新:

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

    Dispatcher.BeginInvoke(...)

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

    更新 2:

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

    【讨论】:

    • 这是一个 STA 线程。这就是我不得不将处理工作转移到后台线程的全部原因 - 调用线程是我们的情况,始终是 MTA。
    • Dispatcher.BeginInvoke() 不会破坏后台线程上 WPF 处理的目的吗?我不想将任务分流回 UI 线程..
    • 我的意思是尝试使用画布的调度程序。试试“theCanvas.Dispatcher.BeginInvoke()”。
    • Dispatcher.BeginInvoke 如果从拥有调度程序的线程调用,它将不会异步运行。在这种情况下,提供的委托只会被添加到调度程序队列的末尾。这使消息循环有机会执行队列中未决的任何其他任务。
    • 您会知道,因为您的代表被调用了。代码将在与之前相同的线程上运行,除了它将与因您对画布的更改而产生的高优先级“UI”代码交错。当最后一个委托完成执行时,您可以使用与旧方案中通知“MTA 线程”相同的通知机制。但是,我认为在尝试之前调试代码以找出真正的原因是值得的。
    【解决方案2】:

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

    【讨论】:

    • ...你能详细说明一下吗? Dispatcher.Run() 通常用于在 WPF UI 线程上执行一些逻辑。我明确希望在后台线程上执行我的代码,不是 UI 线程。
    • 但是,如果您在后台线程上使用 WPF 对象,那么该线程就是 UI 线程。
    • @Scott,你能给我提供一些这样的 MS 文档吗?并不是说我不相信你:-) 我只是想确保我正确理解了使用 WPF 进行后台处理的含义......
    • 不,我不能。但是 Canvas 类继承自 DispatcherObject。这意味着它使用与创建它的线程相关联的调度程序。在这种情况下,这意味着您的 bg 线程。查看 DispatcherObject 的文档
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    相关资源
    最近更新 更多