【问题标题】:Calling Dispatcher.Invoke() on Dispatcher thread在 Dispatcher 线程上调用 Dispatcher.Invoke()
【发布时间】:2014-09-19 11:38:06
【问题描述】:

我在使用 Window.Show 显示 WPF 窗口时遇到问题:

System.InvalidOperationException 未处理 消息:WindowsBase.dll 中出现“System.InvalidOperationException”类型的未处理异常 附加信息:调用线程无法访问此对象,因为其他线程拥有它。

很公平 - 解决此问题的标准方法是使用 Dispatcher.Invoke 确保窗口显示在 Dispatcher 线程上。

奇怪的是,据我所知,代码已经在 Dispatcher 线程上运行了。

这段代码触发了异常:

if (Dispatcher.CurrentDispatcher.Thread != Thread.CurrentThread || 
        Application.Current.Dispatcher.Thread != Thread.CurrentThread)
{
    throw new ApplicationException("Current thread is not Dispatcher");
}

window.Show(); // throws InvalidOperationException

这段代码运行良好:

if (Dispatcher.CurrentDispatcher.Thread != Thread.CurrentThread || 
        Application.Current.Dispatcher.Thread != Thread.CurrentThread)
{
    throw new ApplicationException("Current thread is not Dispatcher");
}

Dispatcher.CurrentDispatcher.Invoke(window.Show);

按照我的理解,如果当前线程是dispatcher线程,那么调用Dispatcher.Invoke应该相当于直接调用方法。显然这是错误的,但有人可以解释原因吗?

为了使问题复杂化,此代码位于通过 COM 从 VB6 应用程序调用的方法中(是的,我知道)。这会产生什么影响?

【问题讨论】:

  • 尝试将 Thread.CurrentThread 与 App.Current.Dispatcher.Thread 进行比较。如果没有看到调用 window.Show() 的完整方法,很难判断您是否在调度程序线程上运行。
  • 对于这样的问题,您无法得到有用的答案。无用的方法是this one。
  • 我试过 Application.Current.Dispatcher 和 Dispatcher.CurrentDispatcher - 它们是一样的。我已经更新了帖子以消除歧义。
  • @roomaroo,您的第一个代码 sn-p Dispatcher.Current.Thread != Thread.CurrentThread 有问题,因为 WPF 中没有 Dispatcher.Current 属性。
  • @Noseratio 谢谢 - VS 在我写问题时冻结了,所以我无法复制和粘贴!

标签: c# wpf com dispatcher


【解决方案1】:

我怀疑这里的问题是第一种情况下的错误 .NET 同步上下文(或缺少同步上下文)。

据我了解,这段代码是从非托管主机调用的,它自然没有在主 UI 线程上安装 .NET 同步上下文。

在第一种情况下试试这个:

System.Diagnostics.Debug.WriteLine(new { System.Threading.SynchronizationContext.Current });
window.Show(); // throws InvalidOperationException

我希望您在调试输出中看到{ Current = null }。

对于第二种情况,这样做:

Dispatcher.CurrentDispatcher.Invoke(() => {
    System.Diagnostics.Debug.WriteLine(new { System.Threading.SynchronizationContext.Current });
    window.Show();
});

这应该输出{ Current = System.Windows.Threading.DispatcherSynchronizationContext }。

【讨论】:

  • 好电话。第一种情况给出 { Current = System.Windows.Threading.SynchronizationContext } 而不是 null,但它不是 DispatcherSynchronizationContext。
  • referencesource.microsoft.com/WindowsBase/R/… 处的代码显示 Dispatcher 在调用 Action 之前更改了 SynchronizationContext。
  • 我遇到了类似原始问题的问题,并正在寻找调试方法。不幸的是,无论哪种情况,我都没有看到 current= null 。查看哪个线程拥有我的对象的正确方法是什么?
  • @Adam,查看哪个线程拥有我的对象的正确方法是什么? - 你指的是什么对象?
  • 感谢您的回复,我的意思是得到“调用线程无法访问此对象,因为不同的线程拥有它”的对象。错误。 (我的调试工作确实表明当前正在运行的线程和 object.Dispatcher.Thread 是相同的。但是我看错了对象,所以现在我认为我的问题的答案是 object.Dispatcher.Thread!)跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多