在我的WPF应用程序中,我与服务器异步通信。因此回调将不会在UI线程中运行,因为我需要在那里做一些WPF(创建InkPresenter对象),我需要它在UI线程上运行。嗯,实际上要求是它在STA公寓模式的线程上运行。我尝试使用STA模式创建一个新线程,但结果是UI线程无法访问InkPresenter,因为它是“由不同的线程拥有”。
我想在回调中做的是使用Dispatcher调用我需要STA的函数。这听起来像是正确的做法吗?我现在这样做,但它仍然失败。在我的回调函数中,我触发了以下函数,该函数现在尝试确保在UI线程上运行已寻址的函数。
private void UpdateAnnotationsForCurrentFrameCollection()
{
if (Dispatcher.CurrentDispatcher.CheckAccess())
{
DoSomethingIncludingInkPresenter();
}
else
{
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal,
new Action(DoSomethingIncludingInkPresenter));
}
}
private void DoSomethingIncludingInkPresenter()
{
var inkPresenter = XamlReader.Parse(_someXamlString) as InkPresenter;
// Do something with the inkPresenter..
}
正如您从示例中看到的,我使用CheckAccess()来确保我只调用该函数(如果它尚未在UI线程上运行)。当我的回调调用此函数时,CheckAccess()始终为true,但Dispatcher.CurrentDispatcher.Thread.ApartmentState
为MTA。为什么?我尝试删除CheckAccess()并始终执行Invoke,但ApartmentState仍然是MTA,并且创建InkPresenter失败。
任何人都可以解释一下我在这里做错了什么吗?我有错误的调度员吗?这是确保在UI线程上运行某些内容的正确方法吗?
答案 0 :(得分:3)
我认为你混淆了2个要求。 WinForms和WPF主线程被标记为STA以启用COM调用(它们可能发生在控件内部。)
您的问题似乎是经典的“UI不是线程安全的”问题,应该通过调度触摸UI的部分来解决。
但是你不应该在CurrentDispatche上调用CheckAccess,而是调用你的目标:
someControl.Dispatcher.CheckAccess
答案 1 :(得分:2)
我认为问题在于你使用了错误的Dispatcher。我使用过的一种经过验证的方法是传递代码执行的控件的Dispatcher。
private void SomeMethod(Dispatcher dispatcher)
{
DoOtherThingsThatCanDoMTA();
dispatcher.Invoke(new Action(()=>
{
DoSomethingThatRequiresSTA();
}));
}
如果无法以某种方式传递Dispatcher,您可以在属性或任何其他方法中公开它。我希望有所帮助。