介绍:
BackgroundWorker是.NET Framework中提供的一个用于简化多线程编程的辅助类,它是一个控件,专门用于执行多线程任务,允许在后台线程中执行耗时的操作,同时保持主线程(通常是用户界面线程)的响应性。
事件与方法:
事件
- DoWork:在后台线程上执行耗时操作的事件。开发人员应在此事件处理程序中编写需要后台执行的代码。
- ProgressChanged:报告操作进度的事件。当后台线程通过ReportProgress方法报告进度时,此事件被触发。开发人员可以在此事件处理程序中更新用户界面以反映进度变化。
- RunWorkerCompleted:异步操作完成时触发的事件。无论操作是成功完成、被取消还是发生异常,此事件都会被触发。开发人员可以在此事件处理程序中执行清理操作并处理操作结果。
方法
- RunAsync:启动异步操作的方法。调用此方法将触发DoWork事件。
- CancelAsync:请求取消异步操作的方法。当调用此方法时,BackgroundWorker将设置
- CancellationPending属性为true,开发人员需要在DoWork事件处理程序中检查此属性并相应地中止操作。
属性
- WorkerReportsProgress:指示是否支持异步报告进度。如果将其设置为true,则可以在异步操作中使用ReportProgress方法报告进度。
- WorkerSupportsCancellation:指示后台操作是否支持取消。当将其设置为true时,可以通过调用CancelAsync方法来请求取消后台操作。
注意事项
- 在DoWork事件中执行耗时的操作时,不能调用UI线程上的控件。如需更新UI上的控件,应在ProgressChanged事件中调用。
- 在RunWorkerCompleted事件中发生的任何异常都会被视为未处理异常,并可能导致应用程序崩溃。因此,开发人员应在此事件处理程序中添加适当的异常处理代码。
- 一个BackgroundWorker只能同时启动一次RunAsync方法。如果尝试再次调用RunAsync方法,将抛出InvalidOperationException异常。如果需要同时执行多个异步操作,可以考虑使用Task类或其他多线程机制来实现。
private BackgroundWorker worker;
public FrmMain()
{
InitializeComponent();
worker = new BackgroundWorker();
worker.DoWork += Worker_DoWork;
worker.ProgressChanged += Worker_ProgressChanged;
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
worker.WorkerReportsProgress = true;
worker.RunWorkerAsync();// 启动异步操作的方法。调用此方法将触发DoWork事件。
Debug.WriteLine($"主线程:{Thread.CurrentThread.ManagedThreadId}");
}
// 异步操作完成时触发的事件。无论操作是成功完成、被取消还是发生异常,此事件都会被触发
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("异步操作已取消!");
}
else if (e.Error != null)
{
MessageBox.Show("异步操作发生错误: " + e.Error.Message);
}
else
{
MessageBox.Show("异步操作已完成!");
}
}
// 报告操作进度的事件
private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Debug.WriteLine((double)e.ProgressPercentage);
}
// 在后台线程上执行耗时操作的事件
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(1000);
Debug.WriteLine($"Worker_DoWork:{Thread.CurrentThread.ManagedThreadId}");
for (int i = 0; i < 10; i++)
{
// 检查是否请求取消
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
Thread.Sleep(1000);
worker.ReportProgress(i);
}
}