如果你有一个需要很长时间才能完成的操作,并且不希望在用户界面中造成延迟,则可以使用 BackgroundWorker 类在另一个线程上运行该操作。
有关此示例中使用的代码的完整列表,请参阅 如何:在后台运行操作。
在后台运行操作
在 Visual Studio 的 Windows 窗体设计器中激活窗体后,将两个 Button 控件从 工具箱 拖动到窗体,然后根据下表设置按钮的
Name
和 Text 属性。按钮 名字 文本 button1
startBtn
启动 button2
cancelBtn
取消 打开“工具箱”,单击“组件”选项卡,然后将 BackgroundWorker 组件拖动到窗体上。
backgroundWorker1
组件显示在 组件托盘中。在 属性 窗口中,将 WorkerSupportsCancellation 属性设置为
true
。在 属性 窗口中,单击“事件”按钮,然后双击 DoWork,RunWorkerCompleted 事件来创建事件处理程序。
将你的耗时代码插入到 DoWork 事件处理程序中。
从参数 DoWorkEventArgs 的 Argument 属性中提取操作所需的任何参数。
将计算结果分配给 DoWorkEventArgs 的 Result 属性。
此结果将可供 RunWorkerCompleted 事件处理程序使用。
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // Do not access the form's BackgroundWorker reference directly. // Instead, use the reference provided by the sender parameter. BackgroundWorker bw = sender as BackgroundWorker; // Extract the argument. int arg = (int)e.Argument; // Start the time-consuming operation. e.Result = TimeConsumingOperation(bw, arg); // If the operation was canceled by the user, // set the DoWorkEventArgs.Cancel property to true. if (bw.CancellationPending) { e.Cancel = true; } }
Private Sub backgroundWorker1_DoWork( _ sender As Object, e As DoWorkEventArgs) _ Handles backgroundWorker1.DoWork ' Do not access the form's BackgroundWorker reference directly. ' Instead, use the reference provided by the sender parameter. Dim bw As BackgroundWorker = CType( sender, BackgroundWorker ) ' Extract the argument. Dim arg As Integer = Fix(e.Argument) ' Start the time-consuming operation. e.Result = TimeConsumingOperation(bw, arg) ' If the operation was canceled by the user, ' set the DoWorkEventArgs.Cancel property to true. If bw.CancellationPending Then e.Cancel = True End If End Sub
在 RunWorkerCompleted 事件处理程序中插入用于检索操作结果的代码。
// This event handler demonstrates how to interpret // the outcome of the asynchronous operation implemented // in the DoWork event handler. private void backgroundWorker1_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled) { // The user canceled the operation. MessageBox.Show("Operation was canceled"); } else if (e.Error != null) { // There was an error during the operation. string msg = String.Format("An error occurred: {0}", e.Error.Message); MessageBox.Show(msg); } else { // The operation completed normally. string msg = String.Format("Result = {0}", e.Result); MessageBox.Show(msg); } }
' This event handler demonstrates how to interpret ' the outcome of the asynchronous operation implemented ' in the DoWork event handler. Private Sub backgroundWorker1_RunWorkerCompleted( _ sender As Object, e As RunWorkerCompletedEventArgs) _ Handles backgroundWorker1.RunWorkerCompleted If e.Cancelled Then ' The user canceled the operation. MessageBox.Show("Operation was canceled") ElseIf (e.Error IsNot Nothing) Then ' There was an error during the operation. Dim msg As String = String.Format("An error occurred: {0}", e.Error.Message) MessageBox.Show(msg) Else ' The operation completed normally. Dim msg As String = String.Format("Result = {0}", e.Result) MessageBox.Show(msg) End If End Sub
实现
TimeConsumingOperation
方法。// This method models an operation that may take a long time // to run. It can be cancelled, it can raise an exception, // or it can exit normally and return a result. These outcomes // are chosen randomly. private int TimeConsumingOperation( BackgroundWorker bw, int sleepPeriod ) { int result = 0; Random rand = new Random(); while (!bw.CancellationPending) { bool exit = false; switch (rand.Next(3)) { // Raise an exception. case 0: { throw new Exception("An error condition occurred."); break; } // Sleep for the number of milliseconds // specified by the sleepPeriod parameter. case 1: { Thread.Sleep(sleepPeriod); break; } // Exit and return normally. case 2: { result = 23; exit = true; break; } default: { break; } } if( exit ) { break; } } return result; }
' This method models an operation that may take a long time ' to run. It can be cancelled, it can raise an exception, ' or it can exit normally and return a result. These outcomes ' are chosen randomly. Private Function TimeConsumingOperation( _ bw As BackgroundWorker, _ sleepPeriod As Integer) As Integer Dim result As Integer = 0 Dim rand As New Random() While Not bw.CancellationPending Dim [exit] As Boolean = False Select Case rand.Next(3) ' Raise an exception. Case 0 Throw New Exception("An error condition occurred.") Exit While ' Sleep for the number of milliseconds ' specified by the sleepPeriod parameter. Case 1 Thread.Sleep(sleepPeriod) Exit While ' Exit and return normally. Case 2 result = 23 [exit] = True Exit While Case Else Exit While End Select If [exit] Then Exit While End If End While Return result End Function
在 Windows 窗体设计器中,双击
startButton
以创建 Click 事件处理程序。在 Click 事件处理程序中为
startButton
调用 RunWorkerAsync 方法。private void startBtn_Click(object sender, EventArgs e) { this.backgroundWorker1.RunWorkerAsync(2000); }
Private Sub startButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles startBtn.Click Me.backgroundWorker1.RunWorkerAsync(2000) End Sub
在 Windows 窗体设计器中,双击
cancelButton
以创建 Click 事件处理程序。在 Click 事件处理程序中为
cancelButton
调用 CancelAsync 方法。private void cancelBtn_Click(object sender, EventArgs e) { this.backgroundWorker1.CancelAsync(); }
Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles cancelBtn.Click Me.backgroundWorker1.CancelAsync() End Sub
在文件的顶部,导入 System.ComponentModel 和 System.Threading 命名空间。
using System; using System.ComponentModel; using System.Drawing; using System.Threading; using System.Windows.Forms;
Imports System.ComponentModel Imports System.Drawing Imports System.Threading Imports System.Windows.Forms
按 F6 生成解决方案,然后按 Ctrl+F5 在调试器外部运行应用程序。
说明
如果按 F5 在调试器下运行应用程序,则调试器捕获并显示
TimeConsumingOperation
方法中引发的异常。 在调试器外部运行应用程序时,BackgroundWorker 将处理异常并将其缓存在 RunWorkerCompletedEventArgs的 Error 属性中。单击 “开始”按钮以运行异步操作,然后单击 “取消”按钮以停止正在运行的异步操作。
每个操作的结果显示在 MessageBox 中。
后续步骤
实现一个在异步操作进行时报告进度的表单。 有关详细信息,请参阅如何:实现使用后台操作的窗体。
实现一个支持组件异步模式的类。 有关详细信息,请参阅 实现基于事件的异步模式。