Использование потока пользовательского интерфейса WPF всегда должно обеспечивать режим квартиры STA, верно? - PullRequest
2 голосов
/ 05 марта 2010

В моем приложении WPF я асинхронно общаюсь с сервером.Следовательно, обратный вызов не будет выполняться в потоке пользовательского интерфейса, и, поскольку мне нужно выполнить некоторые действия в WPF (создать объект InkPresenter), мне нужно, чтобы он выполнялся в потоке пользовательского интерфейса.Ну, на самом деле требование заключается в том, что он запускается в потоке с режимом квартиры STA.Я попытался создать новый поток в режиме STA, но в результате поток пользовательского интерфейса не смог получить доступ к InkPresenter, так как он «принадлежал другому потоку».

В обратном вызове я хочу использовать диспетчер для вызова моей функции, требующей STA.Это звучит как правильный подход?Я делаю это сейчас, но все равно не получается.В моей функции обратного вызова я запускаю следующую функцию, которая теперь пытается обеспечить выполнение указанной функции в потоке пользовательского интерфейса.

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 (), чтобы убедиться, что я вызываю функцию только в том случае, если она еще не запущена в потоке пользовательского интерфейса.Когда мой обратный вызов вызывает эту функцию, CheckAccess () всегда имеет значение true, но Dispatcher.CurrentDispatcher.Thread.ApartmentState - MTA.Зачем?Я пытался удалить CheckAccess () и всегда делал Invoke, но ApartmentState остается MTA, и создание InkPresenter завершается неудачно.

Может кто-нибудь объяснить мне, что я здесь делаю не так?У меня неправильный Диспетчер или что-то еще?Это правильный подход к обеспечению того, чтобы что-то запускалось в потоке пользовательского интерфейса?

Ответы [ 2 ]

3 голосов
/ 05 марта 2010

Я думаю, что вы путаете 2 требования. Основные потоки WinForms и WPF помечены как STA для включения COM-вызовов (и они могут происходить внутри элементов управления).

Ваша проблема, кажется, является классической проблемой "пользовательский интерфейс не является потокобезопасным", и ее следует решить путем отправки частей, которые касаются пользовательского интерфейса.

Но вы не должны вызывать CheckAccess для CurrentDispatche, а для вашей цели:
someControl.Dispatcher.CheckAccess

2 голосов
/ 05 марта 2010

Я думаю, проблема в том, что вы используете неправильный Диспетчер. Один из проверенных и настоящих методов, которые я использовал, - передать Dispatcher элемента управления, в котором выполняется код.

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

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

Если каким-либо образом невозможно передать Dispatcher, вы можете выставить его в свойстве или любым другим способом. Я надеюсь, что это помогает.

...