我们来看个简单的例子,在这里演示调用 WebClient.DownloadStringAsync 方法(这个方法不是 TAP),然后由 WebClient.DownloadStringCompleted 事件通知 UI 更新,这是大多数人都会用的方法。
public
static
Task<byte[]> DownloadDataTask(this WebClient webClient, Uri address)
{
????// Create the task to be returned
????var tcs = new TaskCompletionSource<byte[]>(address);
?
????// Setup the callback event handler
????DownloadDataCompletedEventHandler handler = null;
????handler = (sender, e) => EAPCommon.HandleCompletion(tcs, e, () => e.Result, () => webClient.DownloadDataCompleted -= handler);
????webClient.DownloadDataCompleted += handler;
?
????// Start the async work
????try
????{
????????webClient.DownloadDataAsync(address, tcs);
????}
????catch(Exception exc)
????{
????????// If something goes wrong kicking off the async work,
????????// unregister the callback and cancel the created task
????????webClient.DownloadDataCompleted -= handler;
????????tcs.TrySetException(exc);
????}
?
????// Return the task that represents the async operation
????return tcs.Task;
}
internal
class EAPCommon
{
????internal
static
void HandleCompletion<T>(
????????TaskCompletionSource<T> tcs, AsyncCompletedEventArgs e, Func<T> getResult, Action unregisterHandler)
????{
????????// Transfers the results from the AsyncCompletedEventArgs and getResult() to the
????????// TaskCompletionSource, but only AsyncCompletedEventArg‘s UserState matches the TCS
????????// (this check is important if the same WebClient is used for multiple, asynchronous
????????// operations concurrently). Also unregisters the handler to avoid a leak.
????????if (e.UserState == tcs)
????????{
????????????if (e.Cancelled) tcs.TrySetCanceled();
????????????else
if (e.Error != null) tcs.TrySetException(e.Error);
????????????else tcs.TrySetResult(getResult());
????????????unregisterHandler();
????????}
????}
}