欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

基于事件的异步模式——BackgroundWorker

发布时间:2024/1/17 56 豆豆
生活随笔 收集整理的这篇文章主要介绍了 基于事件的异步模式——BackgroundWorker 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

转自strangeman原文 基于事件的异步模式——BackgroundWorker

 

  实现异步处理的方法很多,经常用的有基于委托的方式,今天记录的是基于事件的异步模式。利用BackgroundWorker组件可以很轻松的实现异步处理,并且该组件还支持事件的取消、进度报告等功能。本文以计算两个数XY的和为例。

  通过反编译可以看到,这个组件内部也是通过异步委托实现的,报告进度、取消事件等运用了事件技术实现,而事件的本质其实就是委托。

程序界面如下图,其中三个文本框分别为两个加数和处理结果,两个按钮为计算和取消,按钮下方为进度条。

引入BackgroundWorker组件,为DoWorkProgressChangedRunWorkerCompleted三个事件指定方法。
WorkerReportsProgress属性设为true,以支持报告进度。
WorkerSupportsCancellation属性设置为true,以支持取消。

public MainForm() {InitializeComponent();this.backgroundWorker1.DoWork += this.BackgroundWorker1DoWork;this.backgroundWorker1.ProgressChanged += this.BackgroundWorker1ProgressChanged;this.backgroundWorker1.RunWorkerCompleted += this.BackgroundWorker1RunWorkerCompleted;this.backgroundWorker1.WorkerReportsProgress = true;this.backgroundWorker1.WorkerSupportsCancellation = true;this.buttonCancel.Enabled = false; }

 

 

 

3. 当点击计算按钮时,调用BackgroundWorkerRunWorkerAsync方法实现异步处理,该方法支持一个object类型的参数。这里用元组Tuple<int,int>传递XY的值。调用RunWorkerAsync方法,将触发DoWork事件。

this.backgroundWorker1.RunWorkerAsync(new Tuple<int,int>(Convert.ToInt32(this.textBoxX.Text), Convert.ToInt32(this.textBoxY.Text)));

 通过反编译看到以下实现代码:

 

public void RunWorkerAsync(object argument) {if (this.isRunning){throw new InvalidOperationException(SR.GetString("BackgroundWorker_WorkerAlreadyRunning"));}this.isRunning = true;this.cancellationPending = false;this.asyncOperation = AsyncOperationManager.CreateOperation(null);this.threadStart.BeginInvoke(argument, null, null);}

 

可以看到其内部也是通过异步委托实现的,其中threadStart的定义:private delegate void WorkerThreadStartDelegate(object argument);就是一个委托类型。

 

4. 当点击取消按钮时,调用BackgroundWorkerCancelAsync方法,这将改变BackgroundWorkerCancellationPending属性的值为ture。当执行OnWork方法时可以根据CancellationPending属性,判断用户是否要取消事件。

this.backgroundWorker1.CancelAsync();  

 再看看其内部:

public void CancelAsync() {if (!this.WorkerSupportsCancellation){throw new InvalidOperationException(SR.GetString("BackgroundWorker_WorkerDoesntSupportCancellation"));}this.cancellationPending = true; }

 

如上面所说,改变只读属性CancellationPending的值为ture

5. 这里在DoWork方法中
根据CancellationPending属性,判断是否取消。若取消,应在方法结束之前将DoWorkEventArgsCancel属性设置为ture。这将用于RunWorkerCompleted事件中判断事件取消还是正常完成。
通过ReportProgress方法报告进度, 调用该方法时传递了一个int类型的参数,该方法将触发ProgressChanged事件。

void BackgroundWorker1DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) {for (int i = 0; i < 10; i++) {System.Threading.Thread.Sleep(500);//模拟耗时操作if (backgroundWorker1.CancellationPending) {e.Cancel = truereturn; } else {backgroundWorker1.ReportProgress(i * 10); }}var t = e.Argument as Tuple<int,int>;e.Result = t.Item1 + t.Item2; }

 

 

 再看报告进度是怎么基于事件实现的:

 

1.我们调用的ReportProgress方法public void ReportProgress(int percentProgress) {this.ReportProgress(percentProgress, null); }2.ReportProgress另一个重载,可以带一个自定义参数,方便传递其他内容,例如一般安装程序中的“正在复制文件”,“正在注册相关组件”提示信息等。public void ReportProgress(int percentProgress, object userState) {if (!this.WorkerReportsProgress){throw new InvalidOperationException(SR.GetString("BackgroundWorker_WorkerDoesntReportProgress"));}ProgressChangedEventArgs progressChangedEventArgs = new ProgressChangedEventArgs(percentProgress, userState);if (this.asyncOperation != null){this.asyncOperation.Post(this.progressReporter, progressChangedEventArgs);return;}this.progressReporter(progressChangedEventArgs);}

 

3.触发事件

private void ProgressReporter(object arg) {this.OnProgressChanged((ProgressChangedEventArgs)arg); }

 

6. ProgressChanged事件,会将控制权交给UI线程。在其实现方法中根据ProgressChangedEventArgsProgressPercentage属性获取进度值。

void BackgroundWorker1ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) {this.progressBar1.Value = e.ProgressPercentage; }

 

7. OnWork退出后,将调用RunWorkerCompleted事件。
根据RunWorkerCompletedEventArgsCancelled属性判断是否正常完成。
根据RunWorkerCompletedEventArgsResult属性获取处理结果。

void BackgroundWorker1RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e){this.textBoxResult.Text = e.Cancelled ? "Canceled" : e.Result.ToString();this.buttonCancel.Enabled = false;this.buttonCalculate.Enabled = true;this.progressBar1.Value = 100;}

 

 

 

8. 完整代码

/** 由SharpDevelop创建。* 用户: David Huang* 日期: 2015/9/8* 时间: 14:54*/ using System; using System.Windows.Forms;namespace BackgroundWorkerTest {/// <summary>/// Description of MainForm./// </summary>public partial class MainForm : Form{public MainForm(){InitializeComponent();this.backgroundWorker1.DoWork += this.BackgroundWorker1DoWork;this.backgroundWorker1.ProgressChanged += this.BackgroundWorker1ProgressChanged;this.backgroundWorker1.RunWorkerCompleted += this.BackgroundWorker1RunWorkerCompleted;this.backgroundWorker1.WorkerReportsProgress = true;this.backgroundWorker1.WorkerSupportsCancellation = true;this.buttonCancel.Enabled = false;}void ButtonCalculateClick(object sender, EventArgs e){this.buttonCalculate.Enabled = false;this.textBoxResult.Text = string.Empty;this.buttonCancel.Enabled = true;this.backgroundWorker1.RunWorkerAsync(new Tuple<int,int>(Convert.ToInt32(this.textBoxX.Text), Convert.ToInt32(this.textBoxY.Text))); }void ButtonCancelClick(object sender, EventArgs e){this.backgroundWorker1.CancelAsync(); }void BackgroundWorker1DoWork(object sender, System.ComponentModel.DoWorkEventArgs e){for (int i = 0; i < 10; i++) {System.Threading.Thread.Sleep(500); if (backgroundWorker1.CancellationPending) {e.Cancel = true;return;} else {backgroundWorker1.ReportProgress(i * 10);}}var t = e.Argument as Tuple<int,int>;e.Result = t.Item1 + t.Item2;}void BackgroundWorker1ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e){this.progressBar1.Value = e.ProgressPercentage;}void BackgroundWorker1RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e){this.textBoxResult.Text = e.Cancelled ? "Canceled" : e.Result.ToString();this.buttonCancel.Enabled = false;this.buttonCalculate.Enabled = true;this.progressBar1.Value = 100;}} } View Code

 


代码下载:点我

 

 

总结

以上是生活随笔为你收集整理的基于事件的异步模式——BackgroundWorker的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。