以WeatherForecast为例. 需求: 用户在窗体上点击一个按钮, 程序去网络上查询天气情况, 并把结果显示在窗体上. 网络查询是一个耗时任务, 在等待结果的同时, 用户将看到一个旋转的时钟动画表示程序正在查询.
模式为:
- 窗口类MainWindow中有耗时函数: string FetchWeatherFromInternet().
- 窗口类MainWindow中包含一个函数 UpdateUIWhenWeatherFetched(string result), 用于把任务结果显示在界面上.
- 当用户点击按钮时, 在 btnFetchWeather_Click() 中,
如果是同步调用, 代码很简单, 如下:
string result = this.FetchWeatherFromInternet();
this.UpdateUserInterface( result );
现在需要异步执行, 稍微麻烦点, 需要用到3个delegate, 其中一个代表要执行的任务, 另一个代表任务结束后的callback, 还有一个代表交给UI执行的任务, 上述代码被替换成如下:
// 代表要执行的异步任务
Func<string> asyncAction = this.FetchWeatherFromInternet();
// 处理异步任务的结果
Action<IAsyncResult> resultHandler = delegate( IAsyncResult asyncResult )
{
//获得异步任务的返回值, 这段代码必须在UI线程中执行
string weather = asyncAction.EndInvoke( asyncResult );
this.UpdateUIWhenWeatherFetched( weather );
};
//代表异步任务完成后的callback
AsyncCallback asyncActionCallback = delegate( IAsyncResult asyncResult )
{
this.Dispatcher.BeginInvoke( DispatcherPriority.Background, resultHandler, asyncResult );
};
//这是才开始执行异步任务
asyncAction.BeginInvoke( asyncActionCallback, null );
=======================================================================
private void ForecastButtonHandler(object sender, RoutedEventArgs e) { this.UpdateUIWhenStartFetchingWeather(); //异步任务封装在一个delegate中, 此delegate将运行在后台线程 Func<string> asyncAction = this.FetchWeatherFromInternet;
//在UI线程中得到异步任务的返回值,并更新UI
//必须在UI线程中执行
Action<IAsyncResult> resultHandler =
delegate(IAsyncResult asyncResult)
{
string weather = asyncAction.EndInvoke(asyncResult);
this.UpdateUIWhenWeatherFetched(weather);
};
//异步任务执行完毕后的callback, 此callback运行在后台线程上.
//此callback会异步调用resultHandler来处理异步任务的返回值. AsyncCallback asyncActionCallback = delegate(IAsyncResult asyncResult) { this.Dispatcher.BeginInvoke(DispatcherPriority.Background, resultHandler, asyncResult); }; //在UI线程中开始异步任务,
//asyncAction(后台线程), asyncActionCallback(后台线程)和resultHandler(UI线程)
//将被依次执行 asyncAction.BeginInvoke(asyncActionCallback, null); } private string FetchWeatherFromInternet() { // Simulate the delay from network access. Thread.Sleep(4000); String weather = "rainy"; return weather; } private void UpdateUIWhenStartFetchingWeather() { // Change the status
this.fetchButton.IsEnabled = false; this.weatherText.Text = ""; } private void UpdateUIWhenWeatherFetched(string weather) { //Update UI text this.fetchButton.IsEnabled = true; this.weatherText.Text = weather; }