在我写这篇文章之前,我以为我知道导致这种异常的原因是什么:
var menu = ViewConfigHelper.CreateObjectFromResource<Menu>(config, baseURI);
if (!menu.Dispatcher.CheckAccess())
{
throw new ArgumentException("Somethign wrong");
}
if (!LayoutRoot.Dispatcher.CheckAccess())
{
throw new ArgumentException("SOmethign wrong");
}
// exception throw here
LayoutRoot.Children.Insert(0, menu);
第一行从嵌入的XAML文件创建一个Menu控件。两个CheckAccess调用都返回true。但是,当执行最后一行时,会抛出一个异常,并显示消息“Caling thread无法访问对象,因为不同的线程拥有它”。上面的代码是在我相信在同一个线程上创建LayoutRoot的InitializeComponent()之后立即调用的方法中执行的。
有人请赐教。我正在尝试创建一个多UI线程WPF应用程序。答案 0 :(得分:4)
您正在反向使用CheckAccess()。你想失去!每次检查前的标志。请参阅CheckAccess() MSDN页面上的示例代码位。
在Winforms世界中,你会做一个InvokeRequired(),它现在与!CheckAccess()相同。在你的情况下,因为两个值都返回true,并且你正在反转它们,所以如果块被击中都没有。
在Winforms世界中扩展一点 ...,正常模式是:
if(InvokeRequired)
{
Invoke(...);
}
else
{
//do work
}
(或者有时在调用后返回,如果它正在调用相同的方法)。
在WPF中,CheckAccess()类似于InvokeRequired,但与InvokeRequired不同......对于更多类似的模式:
if (someUiControl.Dispatcher.CheckAccess())
{
//Doing an update from this thread is safe, so we can do so here.
}
else
{
// This thread does not have access to the UI thread.
// Call the update thread via a Dispatcher.BeginInvoke() call.
}
之间的关键区别是InvokeRequired()返回true表示在当前线程中进行更新是UNSAFE ...而来自CheckAccess()的true表示它是SAFE。