Introduction
使用 .net 內建的元件去實現非同步作業。當一個作業需要花很長的時間去完成,大都會使用背景處理,
這樣使用者還是可以繼續其他的操作,並且 UI 介面也不會鎖死。
當然,有許多方法可以達到背景作業的效果,這邊使用 backgroundworker 元件測試。
Example
001 | public partial class Form1 : Form { |
002 | //宣告 BW 變數 |
003 | private BackgroundWorker _BW; |
004 | //宣告 _Limit 變數,並且設定初值 |
005 | private int _Limit = 100000; |
006 | public Form1() { |
007 | InitializeComponent(); |
008 | } |
009 | private void Form1_Load(object sender, EventArgs e) { |
010 | this.btnStartBackgroundWork.Enabled = true; |
011 | this.btnCancelBackgroundWork.Enabled = false; |
012 | } |
013 | private void btnStartBackgroundWork_Click(object sender, EventArgs e) { |
014 | //關閉 btnStartBackgroundWork 按鈕 |
015 | btnStartBackgroundWork.Enabled = false; |
016 | //開啟 btnCancelBackgroundWork 按鈕 |
017 | btnCancelBackgroundWork.Enabled = true; |
018 | //設定 ProgressBar 最大值 |
019 | toolStripProgressBar1.Maximum = _Limit; |
020 | //建立 BW 物件 |
021 | _BW = new BackgroundWorker(); |
022 | //設定是否支援非同步作業取消 |
023 | _BW.WorkerSupportsCancellation = true; |
024 | //繫結 DoWork 事件,當非同步作業啟動時,會呼叫該事件 |
025 | _BW.DoWork += new DoWorkEventHandler(_BW_DoWork); |
026 | //啟動非同步作業,並將參數傳入 |
027 | //在 DoWork 函式中,參數會由 DoWorkEventArgs 帶出 |
028 | _BW.RunWorkerAsync(0); |
029 | } |
030 | //非同步作業 |
031 | void _BW_DoWork(object sender, DoWorkEventArgs e) { |
032 | //設定 BW 物件可以更新表單資訊報告進度 |
033 | _BW.WorkerReportsProgress = true; |
034 | //繫結 ProgressChanged 事件,當 WorkerReportsProgress 屬性設為 true , |
035 | //會觸發該事件,同時在這麼函式下,可以更新表單資訊 |
036 | _BW.ProgressChanged += new ProgressChangedEventHandler(_BW_ProgressChanged); |
037 | //當背景作業已完成時、取消、例外發生時皆會觸發該事件 |
038 | _BW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_BW_RunWorkerCompleted); |
039 | //呼叫自訂函式 |
040 | DoAdd((BackgroundWorker)sender, e); |
041 | } |
042 | //非同步作業已完成 |
043 | void _BW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { |
044 | if (e.Cancelled) // 如果非同步作業已被取消... |
045 | { |
046 | UpdateProgressBar("非同步作業已被取消。"); |
047 | } else // 如果非同步作業順利完成.... |
048 | { |
049 | UpdateProgressBar("非同步作業順利完成。"); |
050 | } |
051 | } |
052 | private void DoAdd(BackgroundWorker worker, DoWorkEventArgs e) { |
053 | int iComplete = (int)e.Argument; |
054 | while (iComplete < _Limit) { |
055 | //判斷使用者是否已經取消背景作業 |
056 | if (worker.CancellationPending == true) { |
057 | //設定取消事件 |
058 | e.Cancel = true; |
059 | //跳出迴圈 |
060 | break; |
061 | } |
062 | //呼叫這個方法,會觸發 ProgressChanged 事件 |
063 | worker.ReportProgress(iComplete); |
064 |
065 | iComplete++; |
066 | //這邊睡一下,給緩衝去給表單的 UI 重劃, |
067 | //系統會另外開一條執行緒去觸發事件 (_BW_ProgressChanged)。 |
068 | System.Threading.Thread.Sleep(1); |
069 | } |
070 | } |
071 | //在這麼事件裡,可以存取表單的資訊 |
072 | void _BW_ProgressChanged(object sender, ProgressChangedEventArgs e) { |
073 | //若是已經取消背景作業,就不去更新表單資訊, |
074 | //否則會引發 [引動過程的目標傳回例外狀況]。 |
075 | if (((BackgroundWorker)sender).CancellationPending == false) { |
076 | UpdateProgressBar(e.ProgressPercentage); |
077 | UpdateTxtBox(e.ProgressPercentage); |
078 | } |
079 | } |
080 | private void btnCancelBackgroundWork_Click(object sender, EventArgs e) { |
081 | //取消背景作業 |
082 | this.CancelBackgroundWork(); |
083 | } |
084 | private void CancelBackgroundWork() { |
085 | // 在嘗試取消非同步作業前,先判斷非同步作業是否仍在執行中。 |
086 | if (_BW.IsBusy) { |
087 | UpdateProgressBar("非同步作業計算中..."); |
088 | // 呼叫 BackgroundWorker 物件的 CancelAsync 方法來要求取消非同步作業。 |
089 | _BW.CancelAsync(); |
090 | } |
091 | } |
092 | //更新狀態文字 |
093 | private void UpdateProgressBar(string text) { |
094 | toolStripStatusLabel1.Text = text; |
095 | } |
096 | //更新 ProgressBar |
097 | private void UpdateProgressBar(int value) { |
098 | toolStripProgressBar1.Value = value; |
099 | } |
100 | //更新 TxtBox |
101 | private void UpdateTxtBox(int value) { |
102 | textBox1.Text = value.ToString(); |
103 | } |
104 | //關閉表單發生時 |
105 | private void Form1_FormClosing(object sender, FormClosingEventArgs e) { |
106 | //取消背景作業 |
107 | this.CancelBackgroundWork(); |
108 | } |
109
110
沒有留言:
張貼留言