使用异步事件在后台进行计算并报告进度 演练:实现一个使用后台操作的窗体
类在另一个线程中执行这种操作。
即使计算很大的斐波那契数列需要花费大量的时间,但主 UI 线程不会被这种延时中断,并且在计算期间窗体仍会响应。
本演练涉及以下任务:
-
创建一个基于 Windows 的应用程序
-
BackgroundWorker
-
添加异步事件处理程序
-
添加进度报告和取消支持
如何:实现使用后台操作的窗体。
使用设置。 |
第一步是创建项目并设置窗体。
创建使用后台操作的窗体
-
如何:创建新的 Windows 窗体应用程序项目。
-
“是”按钮。
-
91。
-
控件。
-
false。
-
如何:使用设计器创建事件处理程序。
-
resultLabel。
-
控件拖到窗体上。
BackgroundWorker。
利用设计器创建一个 BackgroundWorker
-
拖动到窗体上。
这些事件处理程序将调用在后台运行的计算斐波那契数列的耗时操作。
实现异步事件处理程序
-
如何:使用设计器创建事件处理程序。
-
在这里使用是出于演示的目的,为了说明在应用程序中某项操作可能带来长时间的延迟。
// This is the method that does the actual work. For this // example, it computes a Fibonacci number and // reports progress as it does its work. long ComputeFibonacci(int n, BackgroundWorker worker, DoWorkEventArgs e) { // The parameter n must be >= 0 and <= 91. // Fib(n), with n > 91, overflows a long. if ((n < 0) || (n > 91)) { throw new ArgumentException( "value must be >= 0 and <= 91", "n"); } long result = 0; // Abort the operation if the user has canceled. // Note that a call to CancelAsync may have set // CancellationPending to true just after the // last invocation of this method exits, so this // code will not have the opportunity to set the // DoWorkEventArgs.Cancel flag to true. This means // that RunWorkerCompletedEventArgs.Cancelled will // not be set to true in your RunWorkerCompleted // event handler. This is a race condition. if (worker.CancellationPending) { e.Cancel = true; } else { if (n < 2) { result = 1; } else { result = ComputeFibonacci(n - 1, worker, e) + ComputeFibonacci(n - 2, worker, e); } // Report progress as a percentage of the total task. int percentComplete = (int)((float)n / (float)numberToCompute * 100); if (percentComplete > highestPercentageReached) { highestPercentageReached = percentComplete; worker.ReportProgress(percentComplete); } } return result; }
-
事件处理程序可以使用此结果。
事件与用户界面进行通信。
// This event handler is where the actual, // potentially time-consuming work is done. private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // Get the BackgroundWorker that raised this event. BackgroundWorker worker = sender as BackgroundWorker; // Assign the result of the computation // to the Result property of the DoWorkEventArgs // object. This is will be available to the // RunWorkerCompleted eventhandler. e.Result = ComputeFibonacci((int)e.Argument, worker, e); }
-
事件处理程序中,添加启动异步操作的代码。
private void startAsyncButton_Click(System.Object sender, System.EventArgs e) { // Reset the text in the result label. resultLabel.Text = String.Empty; // Disable the UpDown control until // the asynchronous operation is done. this.numericUpDown1.Enabled = false; // Disable the Start button until // the asynchronous operation is done. this.startAsyncButton.Enabled = false; // Enable the Cancel button while // the asynchronous operation runs. this.cancelAsyncButton.Enabled = true; // Get the value from the UpDown control. numberToCompute = (int)numericUpDown1.Value; // Reset the variable for percentage tracking. highestPercentageReached = 0; // Start the asynchronous operation. backgroundWorker1.RunWorkerAsync(numberToCompute); }
-
控件。
// This event handler deals with the results of the // background operation. private void backgroundWorker1_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { // First, handle the case where an exception was thrown. if (e.Error != null) { MessageBox.Show(e.Error.Message); } else if (e.Cancelled) { // Next, handle the case where the user canceled // the operation. // Note that due to a race condition in // the DoWork event handler, the Cancelled // flag may not have been set, even though // CancelAsync was called. resultLabel.Text = "Canceled"; } else { // Finally, handle the case where the operation // succeeded. resultLabel.Text = e.Result.ToString(); } // Enable the UpDown control. this.numericUpDown1.Enabled = true; // Enable the Start button. startAsyncButton.Enabled = true; // Disable the Cancel button. cancelAsyncButton.Enabled = false; }
调用并中断自身的标记。
实现进度报告
-
true。
-
这将用来跟踪进度。
private int numberToCompute = 0; private int highestPercentageReached = 0;
-
ProgressBar。
// This event handler updates the progress bar. private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { this.progressBar1.Value = e.ProgressPercentage; }
实现取消支持
-
事件处理程序中,添加取消异步操作的代码。
private void cancelAsyncButton_Click(System.Object sender, System.EventArgs e) { // Cancel the asynchronous operation. this.backgroundWorker1.CancelAsync(); // Disable the Cancel button. cancelAsyncButton.Enabled = false; }
-
方法中的代码片段可报告进程并支持取消。
if (worker.CancellationPending) { e.Cancel = true; } ... // Report progress as a percentage of the total task. int percentComplete = (int)((float)n / (float)numberToCompute * 100); if (percentComplete > highestPercentageReached) { highestPercentageReached = percentComplete; worker.ReportProgress(percentComplete); }
此时,您就可以编译并运行斐波那契数列计算器应用程序了。
测试项目
-
按 F5 以编译并运行应用程序。
也可以取消未完成的操作。
这是因为主 UI 线程并不等待计算完成。
组件来在后台执行计算的窗体,可以研究异步操作的其他可能性:
-
对象。
-
如何:使用“线程”窗口。
-
基于事件的异步模式概述。
托管线程处理的最佳做法。