在Dispatcher线程上调用Dispatcher.Invoke()

本文关键字:Dispatcher Invoke 线程 调用 | 更新日期: 2023-09-27 18:22:28

我在使用window显示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应该相当于直接调用该方法。显然这是错误的,但有人能解释为什么吗?

使问题复杂化的是,这段代码在一个方法中,该方法是从VB6应用程序通过COM调用的(是的,我知道)。这会产生什么影响?

在Dispatcher线程上调用Dispatcher.Invoke()

我怀疑这里的问题是第一种情况下错误的.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 }