C# 后台线程编程 - BackgroundWorker
用途
Win Form程序不做特别操作是在GUI线程运行的,如果你有比较耗时的工作,将会Hold住GUI没法更新显示运行状态。
BackgroundWorker 类是你能够另起一个线程,将线程进度汇报给GUI线程,也可以从GUI线程通知这个线程终止。
技术解释
-
WinForm开发界面时,从Toolbox选择BackgroundWorker加到Form。并修改名称(属性》Name)。在这个范例里面我改名字为backgroundWorkerCounter,因为我要让它做一个倒计数。
-
在其属性设置支持WorkerReportProgress和WorkerSupportsCancellation
-
在backgroundWorker属性》事件》Asynchronous》下面3个事件的空白处双击,创建空白的事件响应方法。
-
编程
a. 如下图所示,后台线程的主线工作在bdw_DoWork()里面完成。这个方法里面定义了你的工作、对终止后台工作的响应,并且调用ReportProgress()方法向GUI线程报告进度。
b. 在GUI线程你可以对实例化的bgw如此操作:
RunWorkerAsync(): 启动一个异步线程,不会Hold住界面。如果要向后台程序传递参数,可以在方法调用里面加数据,在后台调用e.Argument获取。详见例程。
CancelAsync(): 通知后台线程终止,实际上就是传递一个布尔标记。
c. 在GUI线程你可以对后台事件如此响应:
bgw_ProgressChanged(): 响应后台ReportProgress进度值变化
bgw_RunWorkerCompleted(): 响应后台运行完毕
范例代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
/// <summary>
/// 显示一个计数的范例,演示Background Worker的编程
/// </summary>
namespace bgwCounter
{
public partial class Form1 : Form
{
/// <summary>
/// 自动生成的Form实例化
/// </summary>
public Form1()
{
InitializeComponent();
}
/// <summary>
/// BackgroundWorker主要工作在此,方法框架是VS自动生成的
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorkerCounter_DoWork(object sender, DoWorkEventArgs e)
{
//从输入变量获得计数起始值
int counterStart = (int) e.Argument;
int counter = 0;
//循环递减到0
for (int i = 0; i < counterStart+1; i++)
{
counter = counterStart - i;
//如果倒计数过程中软件调用了backgroundWorker Cancel,则退出循环
if(backgroundWorkerCounter.CancellationPending==true)
{
e.Cancel = true;
break;
}
//每次循环等待1秒
Thread.Sleep(1000);
//每次循环汇报进度,此处为倒计数值,供显示
backgroundWorkerCounter.ReportProgress(counter);
}
}
/// <summary>
/// backgroundWorker进度更新调用函数,用来显示倒计数值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorkerCounter_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//本方法在GUI线程,更新文本显示的计数值
textBoxCounter.Text = e.ProgressPercentage.ToString();
}
/// <summary>
/// backgroundWorker完成后的扫尾工作
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorkerCounter_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Cancelled==true)
{
//如果因为取消而完成,显示相应信息
labelMessage.Text = "counter cancelled by user";
}
else
{
//否则,即为正常完成倒计数
labelMessage.Text = "count down completed";
}
}
/// <summary>
/// Form中点击Start按钮触发此方法,启动backgroundWorker
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonStart_Click(object sender, EventArgs e)
{
backgroundWorkerCounter.RunWorkerAsync((int) numericUpDownCounterStart.Value);
}
/// <summary>
/// For中Stop按钮触发此方法,向backgroundWorker发出取消执行事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonStop_Click(object sender, EventArgs e)
{
backgroundWorkerCounter.CancelAsync();
}
}
}