2014-09-19 133 views
3

我具有显示使用Window.Show WPF窗口的问题调用Dispatcher.Invoke():上调度线程

System.InvalidOperationException了未处理 消息:类型的未处理的异常“System.InvalidOperationException '发生在WindowsBase.dll 附加信息:调用线程不能访问此对象,因为不同的线程拥有它。

不够公平 - 解决此问题的标准方法是使用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.Invoke应相当于直接调用该方法。显然这是错误的,但有人可以解释为什么?

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

+0

尝试将Thread.CurrentThread与App.Current.Dispatcher.Thread进行比较。很难判断你是否在调度程序线程上运行,而没有看到你正在调用window.Show()的完整方法。 – 2014-09-19 12:19:33

+0

对于这样的问题,您无法获得有用的答案。无益的做法是[这一个](http://blogs.msdn.com/b/calvin_hsia/archive/2007/12/12/6749902.aspx)。 – 2014-09-19 13:14:11

+0

我试过Application.Current.Dispatcher和Dispatcher.CurrentDispatcher - 它们是一样的。我已更新帖子以消除歧义。 – roomaroo 2014-09-19 14:09:59

回答

2

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

+1

良好的通话。第一种情况给出{Current = System.Windows.Threading.SynchronizationContext}而不是null,但它不是DispatcherSynchronizationContext。 – roomaroo 2014-09-19 15:13:43

+1

http://referencesource.microsoft.com/WindowsBase/R/4990431309c71f1a.html上的代码显示Dispatcher在调用Action之前更改了SynchronizationContext。 – roomaroo 2014-09-19 15:14:53

+0

我遇到类似原始问题的东西,并寻找调试方法。不幸的是,在这两种情况下,我都没有看到current = null。查看哪个线程拥有我的对象的正确方法是什么? – Adam 2017-05-06 09:25:46