2

私のWPFアプリケーションでは、サーバーと非同期で通信します。したがって、コールバックはUIスレッドで実行されません。そこで、いくつかのWPF処理(InkPresenterオブジェクトの作成)を行う必要があるため、UIスレッドで実行する必要があります。実際の要件は、STAアパートメントモードのスレッドで実行することです。STAモードで新しいスレッドを作成しようとしましたが、「別のスレッドが所有している」ため、UIスレッドがInkPresenterにアクセスできませんでした。

コールバックで実行したいのは、ディスパッチャーを使用して、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.ApartmentStateMTAです。なんで?CheckAccess()を削除して常にInvokeを実行しようとしましたが、ApartmentStateはMTAのままであり、InkPresenterの作成は失敗します。

ここで私が間違っていることを誰かに説明してもらえますか?間違ったディスパッチャーか何かを持っていますか?これは、UIスレッドで何かが実行されるようにするための正しいアプローチですか?

4

2 に答える 2

3

あなたは2つの要件を混同していると思います。WinFormsとWPFのメインスレッドは、COM呼び出しを有効にするためにSTAとマークされています(コントロール内で発生する可能性があります)。

あなたの問題は古典的な「UIはスレッドセーフではない」問題のようであり、UIに触れる部分をディスパッチすることで解決する必要があります。

ただし、CurrentDispatcheではなくターゲットでCheckAccessを呼び出す必要があります。
someControl.Dispatcher.CheckAccess

于 2010-03-05T08:49:17.320 に答える
2

問題は、間違ったディスパッチャを使用していることだと思います。私が使用した実証済みの方法の1つは、コードが実行されるコントロールのディスパッチャーを渡すことです。

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

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

どういうわけかディスパッチャを渡すことができない場合は、プロパティまたは他のメソッドでディスパッチャを公開できます。それがお役に立てば幸いです。

于 2010-03-05T09:12:46.290 に答える