根据我的理解,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;
}));
Context为null,我得到一个InvalidOperation Exception,说“
调用线程无法访问此对象,因为另一个线程拥有它。我从一个使用UseSynchronizationContext = false执行的WCF服务调用它。可以解释这个行为吗?
答案 0 :(得分:2)
BeginInvoke
和Invoke
最终都会调用名为BeginInvokeImpl
的内部方法来完成工作。区别在于Invoke
然后在返回之前等待操作完成。
另外还有一个区别:如果你已经在UI线程和上,那么你正在使用DispatcherPriority.Send
Invoke
实际上会直接调用该方法,而无需通过{{ 1}},意味着在不经过消息队列的情况下处理操作。 (如果您没有使用BeginInvokeImpl
,那么已排队的所有其他消息的属性都将高于您的操作,将首先处理。)
但是因为你可能不在这里的UI线程上 - 你正在进行一些WCF回调 - 这种特殊情况不适用。因此Send
最终会调用与Invoke
相同的底层实现。
根据您提供的信息,我不得不猜测这里某处缺少细节。您显示的代码应该可以正常工作,除非您的应用程序中有多个UI线程,并且恰好位于BeginInvoke
中的页面不时属于不同的线程。
如果您确实有多个UI线程,那么您正在使用的方法 - 通过当前CurrentPage
对象的调度程序推送所有内容 - 是行不通的,因为您将拥有多个调度程序。您需要为您计划触摸的任何UI元素获取正确的调度程序。
顺便提一下,如果您在某个工作线程或回调上构造UI对象(例如,页面),那么您可能会意外地以多个UI线程结束的一种方式。你有可能在某个地方做过吗?