這樣使用者還是可以繼續其他的操作,並且 UI 介面也不會鎖死。
當然,有許多方法可以達到背景作業的效果,這邊使用 backgroundworker 元件測試。
Example
public partial class Form1 : Form { //宣告 BW 變數 private BackgroundWorker _BW; //宣告 _Limit 變數,並且設定初值 private int _Limit = 100000; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { this.btnStartBackgroundWork.Enabled = true; this.btnCancelBackgroundWork.Enabled = false; } private void btnStartBackgroundWork_Click(object sender, EventArgs e) { //關閉 btnStartBackgroundWork 按鈕 btnStartBackgroundWork.Enabled = false; //開啟 btnCancelBackgroundWork 按鈕 btnCancelBackgroundWork.Enabled = true; //設定 ProgressBar 最大值 toolStripProgressBar1.Maximum = _Limit; //建立 BW 物件 _BW = new BackgroundWorker(); //設定是否支援非同步作業取消 _BW.WorkerSupportsCancellation = true; //繫結 DoWork 事件,當非同步作業啟動時,會呼叫該事件 _BW.DoWork += new DoWorkEventHandler(_BW_DoWork); //啟動非同步作業,並將參數傳入 //在 DoWork 函式中,參數會由 DoWorkEventArgs 帶出 _BW.RunWorkerAsync(0); } //非同步作業 void _BW_DoWork(object sender, DoWorkEventArgs e) { //設定 BW 物件可以更新表單資訊報告進度 _BW.WorkerReportsProgress = true; //繫結 ProgressChanged 事件,當 WorkerReportsProgress 屬性設為 true , //會觸發該事件,同時在這麼函式下,可以更新表單資訊 _BW.ProgressChanged += new ProgressChangedEventHandler(_BW_ProgressChanged); //當背景作業已完成時、取消、例外發生時皆會觸發該事件 _BW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_BW_RunWorkerCompleted); //呼叫自訂函式 DoAdd((BackgroundWorker)sender, e); } //非同步作業已完成 void _BW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled) // 如果非同步作業已被取消... { UpdateProgressBar("非同步作業已被取消。"); } else // 如果非同步作業順利完成.... { UpdateProgressBar("非同步作業順利完成。"); } } private void DoAdd(BackgroundWorker worker, DoWorkEventArgs e) { int iComplete = (int)e.Argument; while (iComplete < _Limit) { //判斷使用者是否已經取消背景作業 if (worker.CancellationPending == true) { //設定取消事件 e.Cancel = true; //跳出迴圈 break; } //呼叫這個方法,會觸發 ProgressChanged 事件 worker.ReportProgress(iComplete); iComplete++; //這邊睡一下,給緩衝去給表單的 UI 重劃, //系統會另外開一條執行緒去觸發事件 (_BW_ProgressChanged)。 System.Threading.Thread.Sleep(1); } } //在這麼事件裡,可以存取表單的資訊 void _BW_ProgressChanged(object sender, ProgressChangedEventArgs e) { //若是已經取消背景作業,就不去更新表單資訊, //否則會引發 [引動過程的目標傳回例外狀況]。 if (((BackgroundWorker)sender).CancellationPending == false) { UpdateProgressBar(e.ProgressPercentage); UpdateTxtBox(e.ProgressPercentage); } } private void btnCancelBackgroundWork_Click(object sender, EventArgs e) { //取消背景作業 this.CancelBackgroundWork(); } private void CancelBackgroundWork() { // 在嘗試取消非同步作業前,先判斷非同步作業是否仍在執行中。 if (_BW.IsBusy) { UpdateProgressBar("非同步作業計算中..."); // 呼叫 BackgroundWorker 物件的 CancelAsync 方法來要求取消非同步作業。 _BW.CancelAsync(); } } //更新狀態文字 private void UpdateProgressBar(string text) { toolStripStatusLabel1.Text = text; } //更新 ProgressBar private void UpdateProgressBar(int value) { toolStripProgressBar1.Value = value; } //更新 TxtBox private void UpdateTxtBox(int value) { textBox1.Text = value.ToString(); } //關閉表單發生時 private void Form1_FormClosing(object sender, FormClosingEventArgs e) { //取消背景作業 this.CancelBackgroundWork(); } }
輸出結果