演练:在后台运行操作

更新:2007 年 11 月

如果有一个需要很长时间才能完成的操作,而且不希望用户界面中出现延迟,则可以使用 BackgroundWorker 类来在另一个线程上运行该操作。

有关此示例中所用代码的完整清单,请参见 如何:在后台运行操作

说明:

显示的对话框和菜单命令可能会与“帮助”中的描述不同,具体取决于您的当前设置或版本。若要更改设置,请在“工具”菜单上选择“导入和导出设置”。有关更多信息,请参见 Visual Studio 设置

在后台运行操作

  1. 当窗体在 Windows 窗体设计器中处于活动状态时,将两个 Button 控件从“工具箱”拖动到窗体中,然后根据下表设置这两个按钮的 Name 和 Text 属性。

    按钮

    名称

    文本

    button1

    startBtn

    启动

    button2

    cancelBtn

    取消

  2. 打开“工具箱”,单击“组件”选项卡,然后将 BackgroundWorker 组件拖动到窗体上。

    backgroundWorker1 组件显示在“组件栏”中。

  3. 在“属性”窗口中,单击“事件”按钮,然后双击 DoWorkRunWorkerCompleted 事件以创建事件处理程序。

  4. 将耗时的代码插入到 DoWork 事件处理程序中。

  5. DoWorkEventArgs 参数的 Argument 属性中提取该操作所需的所有参数。

  6. 将计算的结果赋给 DoWorkEventArgsResult 属性。

    计算结果可供 RunWorkerCompleted 事件处理程序使用。

    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   
    
    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;
        }
    }
    
  7. RunWorkerCompleted 事件处理程序中,插入用来检索操作结果的代码。

    ' 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   
    
    // 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);
        }
    }
    
  8. 实现 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 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
    
    // 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;
    }
    
  9. 在 Windows 窗体设计器中双击 startButton,创建新的 Click 事件处理程序。

  10. 在 startButton 的 Click 事件处理程序中,调用 RunWorkerAsync 方法。

    Private Sub startButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles startBtn.Click
        Me.backgroundWorker1.RunWorkerAsync(2000)
    End Sub
    
    private void startBtn_Click(object sender, EventArgs e)
    {
        this.backgroundWorker1.RunWorkerAsync(2000);
    }
    
  11. 在 Windows 窗体设计器中双击 cancelButton,创建新的 Click 事件处理程序。

  12. 在 cancelButton 的 Click 事件处理程序中,调用 CancelAsync 方法。

    Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles cancelBtn.Click
        Me.backgroundWorker1.CancelAsync()
    End Sub
    
    private void cancelBtn_Click(object sender, EventArgs e)
    {
        this.backgroundWorker1.CancelAsync();
    }
    
  13. 在文件的顶部,导入 System.ComponentModel 和 System.Threading 命名空间。

    Imports System
    Imports System.ComponentModel
    Imports System.Drawing
    Imports System.Threading
    Imports System.Windows.Forms
    
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Threading;
    using System.Windows.Forms;
    
  14. 按 F6 生成解决方案,然后按 Ctrl-F5 在调试器外部运行该应用程序。

说明:

如果按 F5 在调试器中运行应用程序,则调试器将捕捉和显示在 TimeConsumingOperation 方法中引发的异常。当在调试器外部运行应用程序时,BackgroundWorker 将处理该异常并将其缓存在 RunWorkerCompletedEventArgsError 属性中。

  1. 单击“启动”按钮运行异步操作,然后单击“取消”按钮停止正在运行的异步操作。

    每个操作的结果均在 MessageBox 中显示。

后续步骤

请参见

任务

如何:实现使用后台操作的窗体

如何:在后台运行操作

参考

BackgroundWorker

DoWorkEventArgs

其他资源

BackgroundWorker 组件