Windows Phone 8 の Contacts オブジェクトを操作して、非同期メソッド内から SearchAysnc を呼び出しています。SearchAsync では、ハンドラーを SearchCompleted イベントにサブスクライブする必要があり、イベント引数の 1 つを介してその結果を配信します。これは、非同期メソッドがそのジョブを実行するために必要です (これには、他の非同期メソッドの呼び出しが含まれます)。
イベントの非同期完了、つまりイベント パターンと async/await パターンの間のブリッジをどのように待ちますか?
私が思いついた唯一の解決策は、EventWaitHandle を使用し、次のような待機中の Task 内でそれを待機することでした。
using System.Threading;
async Task<string> MyMethod()
{
string result = null;
Contacts cons = new Contacts();
EventWaitHandle handle = new EventWaitHandle(false,EventResetMode.ManualReset);
cons.SearchCompleted += (sender,args) =>
{
// I do all my work on the results of the contact search in this handler
result = SomeOtherSynchronousOperation(args.Results);
// When I'm done, I release the thread which was waiting for the results
handle.Set();
};
cons.SearchAsync(String.Empty, FilterKind.None, "My Contact");
// I can't block this thread (or can I?)
// So, I launch a task whose sole job is to wait
await Task.Run(()=>
{
// This gets released by the Contacts.SearchCompleted handler when its work is finished,
// so that MyMethod can finish up and deliver its result
handle.WaitOne();
}
await DoOtherStuffWithResult(result);
return result;
}
私の実際の解決策(上記のとおりではありません)は機能します。上記のコードは実装されたソリューションを正確に表しているわけではありませんが (おそらくコンパイルの問題が 1 つまたは 2 つ)、概念を表現し、私の質問のポイントを説明するのに役立つはずです。
これが唯一の方法なのか、それともイベント ハンドラーの実行を待機するためのベスト プラクティスに近い方法なのか、そうでない場合は、ここで必要なことを行うための "ベスト プラクティス" は何かという疑問が残ります。
Windows 同期プリミティブは、非同期/待機の世界でまだ使用されていますか?
(提供された回答に基づく)
これは正しいでしょうか?
using Microsoft.Phone.UserData;
string ExtractWhatIWantFromResults(IEnumerable<Contact> results)
{
string result;
// Do my processing on the list of contacts, stuff the results into result
return string;
}
async Task<string> MyMethod()
{
Contacts cons = new Contacts();
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
cons.SearchCompleted += (sender,args) =>
{
tcs.TrySetResult(ExtractWhatIWantFromResults(args.Results));
};
cons.SearchAsync(String.Empty, FilterKind.None, "My Contact");
return tcs.Task;
}