20

WPFコードビハインドイベントハンドラーを想像してみてください。

<Button Click="OnButtonClick" />

C#4では、ハンドラーを次のように宣言します。

private void OnButtonClick(object sender, RoutedEventArgs e) { ... }

asyncC#5では、ハンドラーを宣言できます

private async void OnButtonClick(object sender, RoutedEventArgs e) { ... }

では、WPFはこれで何をしているのでしょうか。数分間検索しても何も見つかりませんでした。

awaitステートメントの後にUIの更新を実行できるようです。これは、タスクがディスパッチャースレッドで続行されることを意味しますか?

エラーが発生した場合、TaskそれはWPFを介して発生しますか、それとも?Dispatcherのみを介して発生しTaskSchedulerますか?

これに理解しておくとよい他の興味深い側面はありますか?

4

2 に答える 2

25

私のasync/awaitイントロが役立つかもしれません。

メソッドは、オペレーターasyncをサポートするためにコンパイラーによって書き直されます。awaitすべてのメソッドは、何らかの操作(まだ完了していないasync)になるまで同期(この場合はUIスレッド)で開始されます。await

デフォルトでは、コンテキストが保存され、操作が完了すると、残りのメソッドはそのコンテキストで実行されるようにスケジュールされます。ここでの「コンテキスト」は、そうでSynchronizationContext.Currentない場合はnullそうであり、そうでない場合はですTaskScheduler.Current。Drewが指摘したように、WPFはDispatcherSynchronizationContextWPFに関連付けられたを提供しますDispatcher

エラー処理について:

WPFイベントハンドラー内にいる場合await、エラー処理は次のようになります。Taskasync void

  • エラーでTask完了します。例外はAggregateException、すべてのTaskエラーと同様に、にラップされます。
  • awaitオペレーターは、Taskエラーで完了したことを確認します。元の例外をアンラップして再スローし、元のスタックトレースを保持します。
  • メソッドビルダーは、メソッドasync voidからエスケープされた例外をキャッチし、メソッドの実行開始時にアクティブだった例外(この場合は同じWPFコンテキスト)async voidに渡します。SynchronizationContextasync void
  • 例外は(元のスタックトレースを使用し、煩わしいAggregateExceptionラッピングなしで)発生しDispatcherます。

これはかなり複雑ですが、イベントハンドラーからasync発生する例外を、通常のイベントハンドラーから発生する例外と実質的に同じにすることを目的としています。

于 2012-09-24T01:57:18.747 に答える
6

部分的な答え。MSDNから:

void returnタイプを持つ非同期メソッドは待機できず、void-returningメソッドの呼び出し元は、メソッドがスローする例外をキャッチできません。

したがって、エラーは。を介してのみ利用できますTaskScheduler

また、イベントハンドラーの登録ではXAML固有の処理は行われません。それはコードで行われた可能性があります:

this.button.Click += OnButtonClick;

または非同期ラムダとしても:

this.button.Click += async (s,e) => { ... };

後のUI更新の安全性については、スレッドごとに設定されているawait内で継続が実行されているようです。SynchronisationContext.CurrentWPFでは、これは、最初にイベントをポンプDispatcherSynchronisationContextしたWPFに結合されています。Dispatcher

于 2012-09-23T23:18:17.820 に答える