這樣使用者還是可以繼續其他的操作,並且 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();
}
}輸出結果