BackgroundWorker 类允许在单独的专用线程上运行操作。 耗时的操作(如下载和数据库事务)在长时间运行时可能会导致用户界面 (UI) 似乎处于停止响应状态。 如果需要能进行响应的用户界面,而且面临与这类操作相关的长时间延迟,则可以使用 BackgroundWorker 类方便地解决问题。
若要在后台执行耗时的操作,请创建一个 BackgroundWorker,侦听那些报告操作进度并在操作完成时发出信号的事件。 可以通过编程方式创建 BackgroundWorker,也可以将它从“工具箱”的“组件”选项卡中拖到窗体上。 如果在 Windows 窗体设计器中创建 BackgroundWorker,则它会出现在组件栏中,而且它的属性会显示在“属性”窗口中。
若要为后台操作做好准备,请添加 DoWork 事件的事件处理程序。 在此事件处理程序中调用耗时的操作。 若要开始此操作,请调用 RunWorkerAsync。 若要收到进度更新的通知,请处理 ProgressChanged 事件。 若要在操作完成时收到通知,请处理 RunWorkerCompleted 事件。
下面指出BackgroundWorker类的常用属性和事件。
重要属性:
CancellationPending——只读,指示应用程序是否已请求取消后台操作。若为真则退出线程。
IsBusy——只读,指示 BackgroundWorker 是否正在运行异步操作
WorkerReportsProgress——读写,该值指示 BackgroundWorker 能否报告进度更新。若为false, 调用ReportProgress方法时会抛出异常
WorkerSupportsCancellation——读写,该值指示 BackgroundWorker 是否支持异步取消。若为false则在取消同步方法CancelAsync时引发InvalidOperationException 异常
//
重要事件:
DoWork——调用 RunWorkerAsync 时发生。
ProgressChanged——调用 ReportProgress 时发生。
RunWorkerCompleted——当后台操作已完成、被取消或引发异常时发生。
重要方法:
CancelAsync——请求取消挂起的后台操作
ReportProgress(Int32,Object)——引发 ProgressChanged 事件
RunWorkerAsync——开始执行后台操作
BackgroundWorker的使用非常简单,从工具箱中拖出即可(当然也可以自己用代码声明一个BackgroundWorker对象)。其使用流程包括三个:
1)DoWork,顾名思义,这个事件里主要进行后台操作,不应设计UI交互
2)ProgressChanged,后台线程的工作有了一定进展的时候,就可以在这里反馈给UI界面显示,这个方法运行于主线程内。
3)RunWorkerCompleted,调用结束后的相关操作。这个方法也位于主线程内。调用结束有三种情况:完成任务、异常退出、取消任务。
具备了以上三部分内容以后,只要适时调用BackgroundWorker的RunWorkerAsync,就会触发DoWork事件开辟后台线程处理数据;而在DoWork中调用ReportProgress报告处理进度时又会触发ProgressChanged事件,可以与UI进行交互。当调用后台线程处理完成或调用CancelAsync方法或发生错误时,又会触发RunWorkerCompleted事件。这样完成了整个流程。
接下来通过一段代码示例说明BackgroundWorker的工作流程
示例代码:
namespace backgroundWorkerTest
{
public partial class Form1 : Form
{
//声明一个BackgroundWorker类的示例,也可以从工具箱中拖动一个BackgroundWorker组件到设计界面
//如果是自己声明的话,则需要重载对应的方法,或为BackgroundWorker对应的事件绑定委托链
//private BackgroundWorker worker = new BackgroundWorker();
public Form1()
{
InitializeComponent();
//要求worker能报告进度更新,否则调用ReportProgress方法时会抛出异常:此 BackgroundWorker 声明它不报告进度。请修改 WorkerReportsProgress 以声明它报告进度。
backgroundWorker1.WorkerReportsProgress = true;
//要求worker支持异步取消,否则在取消同步方法CancelAsync时引发InvalidOperationException 异常
backgroundWorker1.WorkerSupportsCancellation = true;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
/// <summary>
/// DoWork方法将会在BackgroundWorker创建的一个后台线程中运行
/// 所以这里面不要涉及UI操作;也不用使用try catch块,BackgroundWorker能自动探测相关异常
/// </summary>
e.Result = ListNumber(backgroundWorker1, e);
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
/// 这个方法对应的事件运行于主线程内
/// 可以在这里进行UI操作
//显示完成进度
progressBar1.Value = e.ProgressPercentage;
label2.Text = e.ProgressPercentage + “%”;
//列出数字
listBox1.Items.Add(e.UserState.ToString());
}
Private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
///结束任务时调用,结束任务的情况包括:1)完成操作2)异常错误3)取消操作
MessageBox.Show(“完成!”);
}
private int ListNumber(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 1000; i++)
{
if (backgroundWorker1.CancellationPending)//如果已请求取消后台操作,退出
{
e.Cancel = true;
return -1;
}
else
{
System.Threading.Thread.Sleep(1);//交出时间片(很重要,没有这一句会造成死锁)
int percent = i / 10;//计算已完成的百分比
///报告完成进度,引发 ProgressChanged 事件,两种重载形式
///ReportProgress(int percentProcess)
///ReportProgress(int percentProcess,object userState)
///percentProcess为完成进度的百分数,必须为[0,100]间的整数,否则抛出异常
///userState传递到RunWorkerAsync 的状态对象
backgroundWorker1.ReportProgress(percent, i);
}
}
return -1;
}
//开始
private void btnStart_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
//开始同步操作
backgroundWorker1.RunWorkerAsync();
}
}
//暂停
private void btnPause_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
//取消同步操作
backgroundWorker1.CancelAsync();
}
}
}
}