C#中,关于 BackgroundWorker 类的使用

介绍

The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.

To execute a time-consuming operation in the background, create a BackgroundWorker and listen for events that report the progress of your operation and signal when your operation is finished. You can create the BackgroundWorker programmatically or you can drag it onto your form from the Components tab of the Toolbox. If you create the BackgroundWorker in the Windows Forms Designer, it will appear in the Component Tray, and its properties will be displayed in the Properties window.

To set up for a background operation, add an event handler for the DoWork event. Call your time-consuming operation in this event handler. To start the operation, call RunWorkerAsync. To receive notifications of progress updates, handle the ProgressChanged event. To receive a notification when the operation is completed, handle the RunWorkerCompleted event.

注意:在后台线程DoWork()中不要出现UI界面里的对象:

You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events.

BackgroundWorker events are not marshaled across AppDomain boundaries. Do not use a BackgroundWorker component to perform multithreaded operations in more than one AppDomain.

关于参数的传递

If your background operation requires a parameter, call RunWorkerAsync with your parameter. Inside the DoWork event handler, you can extract the parameter from the DoWorkEventArgs.Argument property.

For more information about BackgroundWorker, see How to: Run an Operation in the Background.

复制代码
using System; using System.ComponentModel; using System.Windows.Forms; namespace BackgroundWorkerSimple
{ public partial class Form1 : Form
    { public Form1()
        {
            InitializeComponent();

            backgroundWorker1.WorkerReportsProgress = true; // 允许worker汇报状态
            backgroundWorker1.WorkerSupportsCancellation = true; // 允许worker进行取消操作
        } private void startAsyncButton_Click(object sender, EventArgs e)
        { if (backgroundWorker1.IsBusy != true)
            { // Start the asynchronous operation.  
 backgroundWorker1.RunWorkerAsync(); // 启动worker,DoWork()内的代码自动在后台线程开始运行。
            }
        } private void cancelAsyncButton_Click(object sender, EventArgs e)
        { 
 if (backgroundWorker1.WorkerSupportsCancellation == true)
            { // Cancel the asynchronous operation.  
 backgroundWorker1.CancelAsync(); // 执行这命令后,worker.CancellationPending被设置为True
            }
        } // This event handler is where the time-consuming work is done. 
 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker; for (int i = 1; i <= 10; i++)
            { if (worker.CancellationPending == true)
                {
                    e.Cancel = true; // 接收到用户取消线程操作的命令后,经判断是否允许取消操作,再由e.Cancel传出是否执行”取消“操作。 
 break;
                } else { // Perform a time consuming operation and report progress. System.Threading.Thread.Sleep(500);
                    worker.ReportProgress(i * 10); // 后台线程反馈信息给UI界面线程,会去执行ProgressChanged()里的代码。
                }
            }
        } // This event handler updates the progress. private void 
              backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            resultLabel.Text = (e.ProgressPercentage.ToString() + "%"); // UI界面线程的操作,显示进度、日志等。
        } 
 // This event handler deals with the results of the background operation. private void 
            backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        { if (e.Cancelled == true)
            {
                resultLabel.Text = "Canceled!";
            } else if (e.Error != null)
            {
                resultLabel.Text = "Error: " + e.Error.Message;
            } else { // 线程完成后,在这里显示。
                resultLabel.Text = "Done!";
            }
        }
    }
}
复制代码

在UI界面线程运行的代码:

backgroundWorker1.RunWorkerAsync();
backgroundWorker1.CancelAsync();
backgroundWorker1_ProgressChanged();
backgroundWorker1_RunWorkerCompleted();
在后台线程运行的代码:
backgroundWorker1_DoWork();
worker.ReportProgress();
几个流程: 
1 启动线程
UI界面线程中,用户点击backgroundWorker1.RunWorkerAsync();启动线程,接着自动启动后台线程,执行backgroundWorker1_DoWork();中的代码。
在后台线程中执行worker.ReportProgress();则UI界面线程中会执行backgroundWorker1_ProgressChanged();中的代码;
后台线程执行完毕后,UI界面线程会执行backgroundWorker1_RunWorkerCompleted();
2 取消线程
UI界面线程中,用户点击backgroundWorker1.CancelAsync();发出取消线程的指令;
在后台线程中backgroundWorker1_DoWork()代码中执行以下代码予以响应:
                if (worker.CancellationPending == true)
                {
                    e.Cancel = true; // 接收到用户取消线程操作的命令后,经判断是否允许取消操作,再由e.Cancel传出是否执行”取消“操作。 
 break;
                }

UI界面线程的 

backgroundWorker1_RunWorkerCompleted();将会通过参数e.Cancelled执行代码:
            if (e.Cancelled == true)
            {
                resultLabel.Text = "Canceled!";
            } 
传输参数,用结构体来传输:
backgroundWorker1.RunWorkerAsync(struct arg);
在backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)中,将从参数e中获取传入的参数
struct inArg = (struct)e.Argument
如下:
        private void startBtn_Click(object sender, EventArgs e)
        { this.backgroundWorker1.RunWorkerAsync(2000);
        }

把2000当作参数传入,在DoWork中,用e.Argument获取到这个参数。

复制代码
        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;
            }
        }
复制代码
在后台线程DoWork()中,给e.Result赋值,这个线程执行的结果会传出到UI界面线程:
backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 中的e.Result。