【问题标题】:Threading issue with Dispatcher.Invoke and Dispatcher.BeginInvokeDispatcher.Invoke 和 Dispatcher.BeginInvoke 的线程问题
【发布时间】:2010-12-14 19:13:55
【问题描述】:

据我了解 Dispatcher.Invoke 和 Dispatcher.BeginInvoke 在 UI 线程上执行,唯一的区别是 Invoke 是同步的,而 BeginInvoke 是异步的。我的问题是当我使用这段代码时

 EDisc.App.Current.Dispatcher.
              Invoke(
                              DispatcherPriority.Normal, new Action(delegate
                              {
                                  context = NavigationManager.CurrentPage.DataContext;
                              }));

返回上下文的值。但是使用下面的代码

 EDisc.App.Current.Dispatcher.
              BeginInvoke(
                              DispatcherPriority.Normal, new Action(delegate
                              {
                                  context = NavigationManager.CurrentPage.DataContext;
                              }));

上下文为空,我得到一个 InvalidOperation 异常,说“

调用线程无法访问此对象,因为不同的线程拥有它。我是从使用 UseSynchronizationContext = false 执行的 WCF 服务调用它。有人可以解释这种行为吗?

【问题讨论】:

  • EDisc.App的类型是什么?
  • 是Applicaion Object的类名.Application x:Class="EDisc.App"

标签: wpf


【解决方案1】:

BeginInvokeInvoke 最终都会调用一个名为 BeginInvokeImpl 的内部方法来完成这项工作。不同的是Invoke然后等待操作完成再返回。

还有另一个区别:如果您已经在 UI 线程上并且您正在使用 DispatcherPriority.Send Invoke 实际上会直接调用该方法而不通过 BeginInvokeImpl,这意味着该操作在不通过消息队列的情况下进行处理。 (如果您没有使用Send,则任何其他已排队且具有比您的操作更高的属性的消息将首先得到处理。)

但由于您可能不在此处的 UI 线程上 - 您在一些 WCF 回调上 - 这种特殊情况将不适用。所以Invoke 最终调用了与BeginInvoke 相同的底层实现。

根据您提供的信息,我不得不猜测这里某处缺少细节。您显示的代码应该可以正常工作,除非您的应用程序中有多个 UI 线程,并且恰好位于 CurrentPage 中的页面有时属于不同的线程。

如果您确实有多个 UI 线程,那么您使用的方法 - 通过当前 Application 对象的调度程序推送所有内容 - 将无法正常工作,因为您将拥有多个调度程序。您需要为您计划触摸的任何 UI 元素获取正确的调度程序。

顺便说一句,如果您在某个工作线程或回调上构造一个 UI 对象(例如页面),您可能会意外地使用多个 UI 线程。你有可能在某个地方做过吗?

【讨论】:

  • 我已经使用后台线程进行数据密集型操作。但是,每当我调用有问题的代码时,我的 Ui 都是完全响应的(不涉及后台线程)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 2019-02-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多