web-dev-qa-db-ja.com

WPFのディスパッチャとスレッドの関係

アプリケーションにディスパッチャーがいくつあり、それらがスレッドにどのように関連しているか、またはスレッドから参照されているかは、私には完全には明らかではありません。

私が理解しているように、WPFアプリケーションには2つのスレッド(1つは入力用、もう1つはUI用)と1つのディスパッチャー(UIスレッドに関連付けられている)があります。別のスレッドを作成した場合(「ワーカースレッド」と呼びましょう)、ワーカースレッドで_Dispatcher.CurrentDispatcher_を呼び出すと、どのディスパッチャーが取得されますか?

別のケース:メインスレッドと入力スレッドの2つのスレッドを持つコンソールアプリケーションを想定します。メインスレッドでは、最初に入力スレッドを作成してから、Application.Run()を呼び出します。

_Thread thread = new Thread(new ThreadStart(UserInputThreadFunction));
thread.Start();
Application.Run();
_

コーディネーターは1人ですよね?入力スレッドで、Dispatcher.CurrentDispatcherはメインスレッドのディスパッチャーを返しますか?または、インスタンスをメインスレッドのディスパッチャに取得する適切な方法は何ですか?

WPFアプリケーションに複数のディスパッチャが存在する可能性がありますか?別のディスパッチャを作成するのは理にかなっていますか?

24
j00hi

WPFアプリケーションには2つのスレッドがあります(1つは入力用、もう1つはUI用)

この声明は完全に正しいわけではありません。 WPFアプリケーションには、すべてのUI操作とユーザー入力を処理するUIスレッドが1つだけあります。レンダリングを担当する「隠し」スレッドもありますが、通常、開発者はそれを扱いません。

ディスパッチャ/スレッドの関係は1対1です。つまり、1つのディスパッチャは常に1つのスレッドに関連付けられており、そのスレッドに実行をディスパッチするために使用できます。 Dispatcher.CurrentDispatcherは、現在のスレッドのディスパッチャーを返します。つまり、ワーカースレッドでDispatcher.CurrentDispatcherを呼び出すと、その作業スレッドのディスパッチャーを取得します。

ディスパッチャはオンデマンドで作成されます。つまり、Dispatcher.CurrentDispatcherにアクセスし、現在のスレッドに関連付けられているディスパッチャがない場合は、ディスパッチャが作成されます。

そうは言っても、アプリケーション内のディスパッチャの数は、常にアプリケーション内のスレッドの数以下です。

29
Pavlo Glazkov

WPFアプリケーションには、デフォルトで1つのディスパッチャーしかありません。ディスパッチャは、UI要素との対話を可能にする唯一のスレッドです。それはあなたから実装を抽象化するので、あなたはUIスレッド、すなわちディスパッチャーにいることだけを心配する必要があります。

ワーカースレッドからビジュアルを直接操作しようとしている場合(たとえば、txtBkx.Text = "new"を使用してテキストボックスにテキストを設定する場合)、UIスレッドに切り替える必要があります。

Application.Current.Dispatcher.Invoke(
    () => { txtBkx.Text = "new"; });

または、(UIスレッドで)SynchronizationContext.Currentを使用し、それを使用して、別のスレッドからUIスレッドでデリゲートを実行することもできます。 Dispatcher.CurrentDispatcherが常に設定されているとは限らないことに注意してください。

これで、実際には、同じアプリケーションで異なるWPFウィンドウを作成し、ウィンドウごとに個別のディスパッチャーを作成できます。

Thread thread = new Thread(() =>
{
    Window1 w = new Window1();
    w.Show();

    w.Closed += (sender2, e2) =>
    w.Dispatcher.InvokeShutdown();

    System.Windows.Threading.Dispatcher.Run();
});

thread.SetApartmentState(ApartmentState.STA);
thread.Start();  

補足として、MVVMで覚えておくと、WPFがPropertyChangedイベントをマーシャリングするため、非UIスレッドからモデルを更新し、非UIスレッドからプロパティ変更イベントを発生させることができます。ただし、CollectionChangedの発生はUIスレッド上にある必要があります。

12
user619417

dispatcher は常にスレッドに関連付けられており、スレッドは最大で1つのディスパッチャーを同時に実行できます。スレッドにディスパッチャーは必要ありません。

デフォルトでは、ディスパッチャは1つだけです-UI用。他のディスパッチャを使用することが理にかなっている場合もあれば、そうでない場合もあります。ディスパッチャへの呼び出しを処理するには、ディスパッチャスレッドがDispatcher.Run()メソッドでブロックする必要があります。コンソール入力スレッドなどのスレッドは、呼び出しを処理するために使用できません。

3
vidstige