.net 使用WPF UI线程应该始终确保STA单元模式,对吗?

.net 使用WPF UI线程应该始终确保STA单元模式,对吗?,.net,wpf,invoke,dispatcher,sta,.net,Wpf,Invoke,Dispatcher,Sta,在我的WPF应用程序中,我与服务器异步通信。因此,回调不会在UI线程中运行,因为我需要在那里执行一些WPF操作(创建InkPresenter对象),所以我需要在UI线程上运行回调。实际上,要求它在STA单元模式的线程上运行。我尝试使用STA模式创建一个新线程,但结果是UI线程无法访问InkPresenter,因为它“属于另一个线程” 我想在回调中做的是使用Dispatcher调用需要STA的函数。这听起来像是正确的方法吗?我现在这样做了,但还是失败了。在回调函数中,我触发以下函数,该函数现在尝试

在我的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线程上运行某些东西的正确方法吗

我认为您混淆了两个要求。WinForms和WPF主线程标记为STA以启用COM调用(它们可能发生在控件内部)

您的问题似乎是典型的“UI不是线程安全的”问题,应该通过调度触摸UI的部分来解决

但您不应在CurrentDispatch上调用CheckAccess,而应在目标上调用:

someControl.Dispatcher.CheckAccess

我认为问题在于您使用了错误的调度器。我使用过的一种行之有效的方法是将代码执行的控件的分派器传递给它

private void SomeMethod(Dispatcher dispatcher)
{
  DoOtherThingsThatCanDoMTA();

  dispatcher.Invoke(new Action(()=>
  {
    DoSomethingThatRequiresSTA();
  }));
}

如果无法传递调度程序,可以在属性或任何其他方法中公开它。我希望这能有所帮助。

谢谢!Ehr。。我能麻烦你详细说明一下吗?:-)谢谢但是,这在ViewModel中,因此没有可从中获取调度程序的控件。没有“UI线程的通用调度程序”这样的东西吗?也许答案是我不应该在ViewModel中放置像InkPresenter这样的WPF对象。。?但我可以吗?如果是这样的话,我怎么才能找到正确的调度员呢?这里已经有人问过了,我现在找不到。没时间了。好的,没问题。谢谢你的帮助。我现在有了一个新的想法来测试。@Stian:我找到了这个,但讨论得更多了:谢谢。这可能会经常奏效,但我似乎无法访问正确的调度程序。我将尝试另一种方法,但我感谢您在这方面的投入。