BackgroundWorker类中主要用到的有这列属性、方法和事件:
重要属性:
1、CancellationPending获取一个值,指示应用程序是否已请求取消后台操作。通过在DoWork事件中判断CancellationPending属性可以认定是否需要取消后台操作(也就是结束线程);
2、IsBusy获取一个值,指示 BackgroundWorker 是否正在运行异步操作。程序中使用IsBusy属性用来确定后台操作是否正在使用中;
3、WorkerReportsProgress获取或设置一个值,该值指示BackgroundWorker能否报告进度更新
4、WorkerSupportsCancellation获取或设置一个值,该值指示 BackgroundWorker 是否支持异步取消。设置WorkerSupportsCancellation为true使得程序可以调用CancelAsync方法提交终止挂起的后台操作的请求;
重要方法:
1、CancelAsync请求取消挂起的后台操作
2、RunWorkerAsync开始执行后台操作
3、ReportProgress引发ProgressChanged事件
重要事件:
1、DoWork调用 RunWorkerAsync 时发生
2、ProgressChanged调用 ReportProgress 时发生
3、RunWorkerCompleted当后台操作已完成、被取消或引发异常时发生
另外还有三个重要的参数是RunWorkerCompletedEventArgs以及DoWorkEventArgs、ProgressChangedEventArgs。
BackgroundWorker的各属性、方法、事件的调用机制和顺序:
![C# <wbr>winform <wbr>backgroundWorker用法小结 <wbr> <wbr>(转)](https://i-blog.csdnimg.cn/blog_migrate/75a9ce2af47ccda8d3ed40bbc19f4969.jpeg)
从上图可见在整个生活周期内发生了3次重要的参数传递过程:
参数传递1:此次的参数传递是将RunWorkerAsync(Object)中的Object传递到DoWork事件的DoWorkEventArgs.Argument,由于在这里只有一个参数可以传递,所以在实际应用往封装一个类,将整个实例化的类作为RunWorkerAsync的Object传递到DoWorkEventArgs.Argument;
参数传递2:此次是将程序运行进度传递给ProgressChanged事件,实际使用中往往使用给方法和事件更新进度条或者日志信息;
参数传递3:在DoWork事件结束之前,将后台线程产生的结果数据赋给DoWorkEventArgs.Result一边在RunWorkerCompleted事件中调用RunWorkerCompletedEventArgs.Result属性取得后台线程产生的结果。
另外从上图可以看到DoWork事件是在后台线程中运行的,所以在该事件中不能够操作用户界面的内容,如果需要更新用户界面,可以使用ProgressChanged事件及RunWorkCompleted事件来实现。
明白了BagkgroundWorker的事件调用顺序和参数传递机制之后在使用该组件用于多线程编程的时候就可以轻松许多了。
//我们假设获取的记录数固定,我们为此定义一个常量:
private static int MaxRecords = 100;
private void Form1_Load(object sender, EventArgs e)
{
}
/// <summary>
/// 开始
/// </summary>
private void button1_Click(object sender, EventArgs e)
{
if (this.backgroundWorker1.IsBusy)
{
MessageBox.Show("正在执行");
return;
}
this.textBox1.Clear();
//当Start按钮被点击后,RunWorkerAsync方法被掉调用,我们定义的常量(MaxRecords )当作参数被掺入。
//随后,将会触发其DoWork事件
this.backgroundWorker1.RunWorkerAsync(MaxRecords);
this.button1.Enabled = false;
this.button2.Enabled = true;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
//调用RetrieveData方法逐条获取数据
e.Result = this.RetrieveData(this.backgroundWorker1, e);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
throw;
}
}
private int RetrieveData(BackgroundWorker worker, DoWorkEventArgs e)
{
int maxRecords = (int)e.Argument;
int percent = 0;
for (int i = 1; i <= maxRecords; i++)
{
if (worker.CancellationPending)
{
return i;
}
percent = (int)(((double)i / (double)maxRecords) * 100);
worker.ReportProgress(percent, new KeyValuePair<int, string>(i, Guid.NewGuid().ToString()));
System.Threading.Thread.Sleep(100);
}
return maxRecords;
}
//这些操作需要操作UI上的控件,只能在Main Thread中进行。
//如果在RetrieveData方法进行的话,由于该方式是一个异步方法,是会抛出异常的
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
KeyValuePair<int, string> record = (KeyValuePair<int, string>)e.UserState;
this.label1.Text = string.Format("There are {0} records retrieved!", record.Key);
this.progressBar1.Value = e.ProgressPercentage;
this.textBox1.AppendText(record.Value+"\r\n");
}
private void button2_Click(object sender, EventArgs e)
{
this.backgroundWorker1.CancelAsync();//请求结束后台操作
}
//如果操作正常地结束,BackgroundWorker的RunWorkerCompleted会被触发
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
try
{
this.label1.Text = string.Format("Total records: {0}", e.Result);
this.button1.Enabled = true;
this.button2.Enabled = false;
}
catch (TargetInvocationException ex)
{
MessageBox.Show(ex.InnerException.GetType().ToString());
}
}