异步编程:在WPF应用中使用BackgroundWorker和CancellationToken

在现代应用程序开发中,后台任务的管理和调度是提高应用响应性和用户体验的关键。对于使用Windows Presentation Foundation (WPF) 的开发者来说,BackgroundWorker类提供了一种机制来执行后台任务,同时保持UI的响应性。然而,随着Task Parallel Library (TPL) 的引入,后台任务的创建和管理变得更加简单和高效。

在TPL出现之前,创建和管理后台任务,尤其是在WinForm和WPF应用程序中,需要程序员手动处理这些任务的代码。BackgroundWorker类提供了一种预定义的机制来同步后台和UI任务,但它涉及到理解BackgroundWorker是如何提供这些能力的(使用异步回调模型)。BackgroundWorker是对以临时方式处理这些编程任务的改进,但现在有了更新、更好的模型。所有这些功能现在都由新的TPL和CancellationToken机制提供。

使用代码

本文附带的简单应用程序演示了如何使用TPL在WPF应用程序中添加后台处理和进度条。应用程序使用一个低效的递归算法来计算斐波那契数列的第n项,这是一个长时间运行过程的完美示例。滑块条上的值大于40将需要足够的时间来允许在操作完成之前取消操作。滑块条用于设置要计算的数列中的元素编号。提供了两个按钮,"开始异步"和"取消异步",这两个按钮的功能是自解释的。计算结果显示在文本框中。

"开始异步"按钮的处理程序包含启动后台进程的算法的代码。它还创建了一个CancellationToken,该Token传递给后台进程,以便它可以测试取消请求。实际算法包含在ComputeFibonacci方法中。正如源代码中所看到的,添加异步功能到代码中不需要太多改动。

private void StartAsyncButton_Click(object sender, RoutedEventArgs e) { tokenSource = new CancellationTokenSource(); var ct = tokenSource.Token; Task fibTask = Task.Factory.StartNew(() => ComputeFibonacci(numberToCompute, ct, UISyncContext), ct); fibTask.ContinueWith((antecedent) => { if (ct.IsCancellationRequested) { ManageDisplay("已取消", false); } else { ManageDisplay(fibTask.Result.ToString(), false); } }, UISyncContext); }

要启用取消操作,需要遵循以下规则:

  1. 在将引发取消请求的线程中创建CancellationTokenSource,在示例中这是UI线程。
  2. 创建CancellationToken并将其作为参数传递给长时间运行的方法(ComputeFibonacci)和运行该方法的任务(fibTask)。

private void CancelAsyncButton_Click(object sender, RoutedEventArgs e) { tokenSource.Cancel(); }

创建后台任务

接下来,需要启动后台进程,但首先需要保存UI上下文以用于同步目的:

var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext(); Task fibTask = Task.Factory.StartNew(() => ComputeFibonacci(numberToCompute, ct, UISyncContext), ct);

最后,需要链接一个任务来显示ComputeFibonacci方法的结果,这是TPL的一个特性:

fibTask.ContinueWith((antecedent) => { if (ct.IsCancellationRequested) { ManageDisplay("已取消", false); } else { ManageDisplay(fibTask.Result.ToString(), false); } }, UISyncContext);

更新进度条

更新进度条的规则很简单:

  1. 将UI线程传递给长时间运行的方法以进行同步。
  2. 将进度条更新包装在与UI线程同步的任务中。

private long ComputeFibonacci(int n, CancellationToken token, TaskScheduler uiTask) { token.ThrowIfCancellationRequested(); // 执行斐波那契计算... if (percentComplete > highestPercentageReached) { highestPercentageReached = percentComplete; Task.Factory.StartNew(() => { progressBar1.Value = highestPercentageReached; }, token, TaskCreationOptions.AttachedToParent, uiTask); } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485