37

我正在构建一个 WPF 应用程序。我正在与服务器端进行一些异步通信,并在客户端使用事件聚合和 Prism。这两件事都会导致生成不是 UI 线程的新线程。如果我尝试在这些回调和事件处理程序线程上执行“WPF 操作”,那么世界将分崩离析,现在它已经开始这样做了。

首先,我在尝试从服务器的回调中创建一些 WPF 对象时遇到了问题。有人告诉我线程需要在 STA 模式下运行。现在我正在尝试更新 Prism 事件处理程序中的一些 UI 数据,我被告知:

调用者无法访问该线程,因为另一个线程拥有它。

所以; 在 WPF 中做正确的事情的关键是什么?我已经阅读了这篇 MSDN 帖子中的 WPF Dispatcher 。我开始明白了,但我还不是巫师。

  1. 当我需要运行一些我不确定是否会在 UI 线程上调用的东西时,总是使用 Dispatcher.Invoke 的关键是什么?
  2. 如果它实际上是在 UI 线程上调用的,并且无论如何我都执行 Dispatcher.Invoke,这有关系吗?
  3. Dispatcher.Invoke = 同步。Dispathcher.BeginInvoke = 异步?
  4. Dispatcher.Invoke 会请求 UI 线程,然后停止等待吗?响应速度较慢的程序是不好的做法和风险吗?
  5. 无论如何,我如何获得调度员?Dispatcher.CurrentDispatcher 是否总是给我代表 UI 线程的调度程序?
  6. 是否会存在多个 Dispatcher,或者“Dispatcher”是否与应用程序的 UI 线程基本相同?
  7. BackgroundWorker 是怎么回事?我什么时候改用这个?我认为这总是异步的?
  8. 在 UI 线程上运行的所有内容(通过被调用)是否会在 STA 单元模式下运行?即,如果我有一些需要在 STA 模式下运行的东西 - Dispatcher.Invoke 就足够了吗?

有人想为我澄清事情吗?有没有相关推荐之类的?谢谢!

4

1 回答 1

40

一个一个地检查你的每个问题:

  1. 不完全的; 您应该只在必要时调用 UI 线程。见#2。
  2. 是的,这很重要。你不应该只是自动Invoke的一切。关键是仅在必要时调用 UI 线程。为此,您可以使用Dispatcher.CheckAccess方法。
  3. 那是对的。
  4. 也是正确的,是的,您确实冒着响应速度较慢的程序的风险。大多数情况下,您不会看到严重的性能损失(我们谈论的是上下文切换的毫秒数),但只有Invoke在必要时才应该这样做。话虽如此,在某些时候这是不可避免的,所以不,我不会说这是不好的做法。这只是您不时遇到的问题的一种解决方案。
  5. 在我所见过的每一个案例中,我都应得的Dispatcher.CurrentDispatcher。对于复杂的场景,这可能还不够,但我(个人)还没有看到它们。
  6. 不完全正确,但这种思路不会造成任何伤害。让我这样说吧:Dispatcher 可以用来获得对应用程序 UI 线程的访问权限。但它本身并不是 UI 线程。
  7. BackgroundWorker通常在您有一个耗时的操作并希望在后台运行该操作时保持响应式 UI 时使用。通常,您不会使用 BackgroundWorker来代替Invoke,而是将 BackgroundWorkerInvoke 结合使用。也就是说,如果您需要更新 BackgroundWorker 中的某些 UI 对象,您可以调用 UI 线程,执行更新,然后返回原始操作。
  8. 是的。根据定义,WPF 应用程序的 UI 线程必须在单线程单元中运行。

有很多要说的BackgroundWorker,我相信很多问题已经涉及到它,所以我不会太深入。如果您好奇,请查看MSDN 页面的 BackgroundWorker 类

于 2010-03-04T21:39:15.997 回答