基于事件的异步模式——BackgroundWorker
轉自strangeman原文 基于事件的異步模式——BackgroundWorker
?
實現異步處理的方法很多,經常用的有基于委托的方式,今天記錄的是基于事件的異步模式。利用BackgroundWorker組件可以很輕松的實現異步處理,并且該組件還支持事件的取消、進度報告等功能。本文以計算兩個數X、Y的和為例。
通過反編譯可以看到,這個組件內部也是通過異步委托實現的,報告進度、取消事件等運用了事件技術實現,而事件的本質其實就是委托。
程序界面如下圖,其中三個文本框分別為兩個加數和處理結果,兩個按鈕為計算和取消,按鈕下方為進度條。
引入BackgroundWorker組件,為DoWork、ProgressChanged、RunWorkerCompleted三個事件指定方法。
將WorkerReportsProgress屬性設為true,以支持報告進度。
將WorkerSupportsCancellation屬性設置為true,以支持取消。
?
?
?
3. 當點擊計算按鈕時,調用BackgroundWorker的RunWorkerAsync方法實現異步處理,該方法支持一個object類型的參數。這里用元組Tuple<int,int>傳遞X、Y的值。調用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. 當點擊取消按鈕時,調用BackgroundWorker的CancelAsync方法,這將改變BackgroundWorker的CancellationPending屬性的值為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屬性,判斷是否取消。若取消,應在方法結束之前將DoWorkEventArgs的Cancel屬性設置為ture。這將用于RunWorkerCompleted事件中判斷事件取消還是正常完成。
通過ReportProgress方法報告進度, 調用該方法時傳遞了一個int類型的參數,該方法將觸發ProgressChanged事件。
?
?
?再看報告進度是怎么基于事件實現的:
?
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線程。在其實現方法中根據ProgressChangedEventArgs的ProgressPercentage屬性獲取進度值。
void BackgroundWorker1ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) {this.progressBar1.Value = e.ProgressPercentage; }?
7. OnWork退出后,將調用RunWorkerCompleted事件。
根據RunWorkerCompletedEventArgs的Cancelled屬性判斷是否正常完成。
根據RunWorkerCompletedEventArgs的Result屬性獲取處理結果。
?
?
?
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的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 匿名内部类理解
- 下一篇: 关于Keil-MDK