基于事件的异步模式——BackgroundWorker
轉(zhuǎn)自strangeman原文 基于事件的異步模式——BackgroundWorker
?
實(shí)現(xiàn)異步處理的方法很多,經(jīng)常用的有基于委托的方式,今天記錄的是基于事件的異步模式。利用BackgroundWorker組件可以很輕松的實(shí)現(xiàn)異步處理,并且該組件還支持事件的取消、進(jìn)度報(bào)告等功能。本文以計(jì)算兩個(gè)數(shù)X、Y的和為例。
通過(guò)反編譯可以看到,這個(gè)組件內(nèi)部也是通過(guò)異步委托實(shí)現(xiàn)的,報(bào)告進(jìn)度、取消事件等運(yùn)用了事件技術(shù)實(shí)現(xiàn),而事件的本質(zhì)其實(shí)就是委托。
程序界面如下圖,其中三個(gè)文本框分別為兩個(gè)加數(shù)和處理結(jié)果,兩個(gè)按鈕為計(jì)算和取消,按鈕下方為進(jìn)度條。
引入BackgroundWorker組件,為DoWork、ProgressChanged、RunWorkerCompleted三個(gè)事件指定方法。
將WorkerReportsProgress屬性設(shè)為true,以支持報(bào)告進(jìn)度。
將WorkerSupportsCancellation屬性設(shè)置為true,以支持取消。
?
?
?
3. 當(dāng)點(diǎn)擊計(jì)算按鈕時(shí),調(diào)用BackgroundWorker的RunWorkerAsync方法實(shí)現(xiàn)異步處理,該方法支持一個(gè)object類(lèi)型的參數(shù)。這里用元組Tuple<int,int>傳遞X、Y的值。調(diào)用RunWorkerAsync方法,將觸發(fā)DoWork事件。
this.backgroundWorker1.RunWorkerAsync(new Tuple<int,int>(Convert.ToInt32(this.textBoxX.Text), Convert.ToInt32(this.textBoxY.Text)));
?通過(guò)反編譯看到以下實(shí)現(xiàn)代碼:
?
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);}?
可以看到其內(nèi)部也是通過(guò)異步委托實(shí)現(xiàn)的,其中threadStart的定義:private?delegate?void?WorkerThreadStartDelegate(object?argument);就是一個(gè)委托類(lèi)型。
?
4. 當(dāng)點(diǎn)擊取消按鈕時(shí),調(diào)用BackgroundWorker的CancelAsync方法,這將改變BackgroundWorker的CancellationPending屬性的值為ture。當(dāng)執(zhí)行OnWork方法時(shí)可以根據(jù)CancellationPending屬性,判斷用戶(hù)是否要取消事件。
this.backgroundWorker1.CancelAsync();??
?再看看其內(nèi)部:
public void CancelAsync() {if (!this.WorkerSupportsCancellation){throw new InvalidOperationException(SR.GetString("BackgroundWorker_WorkerDoesntSupportCancellation"));}this.cancellationPending = true; }?
如上面所說(shuō),改變只讀屬性CancellationPending的值為ture。
5. 這里在DoWork方法中
根據(jù)CancellationPending屬性,判斷是否取消。若取消,應(yīng)在方法結(jié)束之前將DoWorkEventArgs的Cancel屬性設(shè)置為ture。這將用于RunWorkerCompleted事件中判斷事件取消還是正常完成。
通過(guò)ReportProgress方法報(bào)告進(jìn)度, 調(diào)用該方法時(shí)傳遞了一個(gè)int類(lèi)型的參數(shù),該方法將觸發(fā)ProgressChanged事件。
?
?
?再看報(bào)告進(jìn)度是怎么基于事件實(shí)現(xiàn)的:
?
1.我們調(diào)用的ReportProgress方法public void ReportProgress(int percentProgress) {this.ReportProgress(percentProgress, null); }2.ReportProgress另一個(gè)重載,可以帶一個(gè)自定義參數(shù),方便傳遞其他內(nèi)容,例如一般安裝程序中的“正在復(fù)制文件”,“正在注冊(cè)相關(guān)組件”提示信息等。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.觸發(fā)事件
private void ProgressReporter(object arg) {this.OnProgressChanged((ProgressChangedEventArgs)arg); }?
6. ProgressChanged事件,會(huì)將控制權(quán)交給UI線程。在其實(shí)現(xiàn)方法中根據(jù)ProgressChangedEventArgs的ProgressPercentage屬性獲取進(jìn)度值。
void BackgroundWorker1ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) {this.progressBar1.Value = e.ProgressPercentage; }?
7. OnWork退出后,將調(diào)用RunWorkerCompleted事件。
根據(jù)RunWorkerCompletedEventArgs的Cancelled屬性判斷是否正常完成。
根據(jù)RunWorkerCompletedEventArgs的Result屬性獲取處理結(jié)果。
?
?
?
8. 完整代碼
/** 由SharpDevelop創(chuàng)建。* 用戶(hù): David Huang* 日期: 2015/9/8* 時(shí)間: 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?
代碼下載:點(diǎn)我
?
?
總結(jié)
以上是生活随笔為你收集整理的基于事件的异步模式——BackgroundWorker的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java 匿名内部类理解
- 下一篇: 关于Keil-MDK