2012-09-23 5 views
11

は、WPFのコードビハインドイベントハンドラを想像してみてC#5であなたがasyncハンドラに意義5

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

を宣言することができますので、WPFはこれで何をしているのですか?何分か検索しても、何も上向きませんでした。

await文の後にUIの更新を行うことは可能です。これはタスクがDispatcherスレッド上で継続されることを意味しますか?

Taskにエラーが発生した場合は、WPF DispatcherまたはTaskSchedulerを経由して発生しますか?

他にも興味深い点がありますか?

答えて

19

私のasync/await introが役に立ちます。

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

デフォルトでは、コンテキストが保存され、操作が完了すると、残りのメソッドはそのコンテキストで実行がスケジュールされます。 null以外の場合は、TaskScheduler.Currentです。 Drew氏が指摘しているように、WPFはDispatcherSynchronizationContextを提供しており、これはWPF Dispatcherに関連付けられています。エラー処理について

:エラーと

  • Task完了:

    あなたWPF async voidイベントハンドラ内Taskawaitは、エラー処理はこのように書き

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

は、これはかなり複雑ですが、その意図は、通常のイベントハンドラから発生した例外として、実質的に同じであることasyncイベントハンドラから発生した例外を持つことです。

+0

ありがとうスティーブン。イニシエータのコンテキストが保存されているということは、私が見逃していたものです。私は本当に他のアプローチが理にかなっているとは思えません。 –

2

部分的な回答です。 MSDNから:

ボイド戻り値の型を持つ非同期メソッドを待つことができない、とボイドを返すメソッドの呼び出し元は、メソッドがスローする例外をキャッチすることはできません。

したがって、エラーはTaskSchedulerでのみ利用可能です。

また、イベントハンドラの登録にはXAML固有のものはありません。これは、コード内で行われている可能性:

this.button.Click += OnButtonClick; 

あるいは非同期ラムダとして:UIのアップデートの安全性については

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

awaitた後、継続がSynchronisationContext.Current内で実行されているようだ、これスレッドごとに設定されます。 WPFでは、最初はイベントをポンピングするWPF Dispatcherに結合されたDispatcherSynchronisationContextです。