使用BackgroundWorker跨執行緒對控件做控制,不再讓迴圈當掉你的程式
在.Net中,微軟給了大家非常好用的工具:BackgroundWorker、System.Threading,本篇的主題先以BackgroundWorker為主角,下次再介紹System.Threading。
你可以在工具列中找到BackgroundWorker的蹤跡,但並不是每一種專案類型都有,像是智慧型裝置相關的專案就沒有此工具可用,必須乖乖的使用System.Threading,我們以WindowsFormsApplication為主要的範例專案。
主題開始之前,先提供一個很多新手常發生的錯誤:
private void Form1_Load(object sender, EventArgs e)
{
for (; ; )
textBox1.Text = DateTime.Now.ToString();
}
這個錯誤的範例保證可以Compile,也絕對可以Debug,執行檔也絕對可以執行,但是執行後一定馬上當掉,因為這個程式的執行緒都被一個無線迴圈給卡死了,沒有空閒去做別人的工作,理所當然程式就擋掉了。
接著是正確使用BackgroundWorker的設計方法:
1.從工具列中將BackgroundWorker拉出來,設置兩個動作事件分別為DoWork、ProgressChanged,另外拉出兩個Button,一個是Start另一個是Stop。
2.在Form的Load事件中必須要設定BackgroundWorker的WorkerSupportsCancellation屬性,確定BackgroundWorker會支援取消作業,也可以點選BackgroundWorker在屬性列中直接更改。
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.WorkerSupportsCancellation = true;
}
3.在DoWork事件中加入以下程式碼:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (; ; )
{
try
{
backgroundWorker1.ReportProgress(0);
System.Threading.Thread.Sleep(1000);
}
catch (Exception)
{
break;
}
}
}
另外補充Bill Chung補充修改後的程式碼,比較嚴謹,給大家參考:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (; ; )
{
if (backgroundWorker1.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
try
{
backgroundWorker1.ReportProgress(0);
System.Threading.Thread.Sleep(1000);
}
catch (Exception)
{
e.Cancel = true;
break;
}
}
}
}
4.另外在ProgressChanged事件中加入程式碼如下:
把所有你想要做的事情都寫在ProgressChanged,但是這裡就不要再寫一個無線迴圈或是會打死結的程式了,不然一樣會卡死在裡頭唷。
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
textBox1.Text =DateTime.Now.ToString();
}
5.接著在Start與Stop的Click事件中分別啟動與取消BackgroundWorker:
Start
private void button1_Click(object sender, EventArgs e)
{
if (this.backgroundWorker1.IsBusy != true)
{
this.backgroundWorker1.WorkerReportsProgress = true;
this.backgroundWorker1.RunWorkerAsync();
}
}
IsBusy是確認BackgroundWorker是否已經被啟動了,以免重覆啟動造成錯誤。
Stop
private void button2_Click(object sender, EventArgs e)
{
this.backgroundWorker1.WorkerReportsProgress = false;
this.backgroundWorker1.CancelAsync();
this.backgroundWorker1.Dispose();
}
Dispose()是用來釋放BackgroundWorker,其實在這個範例中並不需要使用,但是當做的事情很多時,還是必須要是放一下。
以上就是如何使用BackgroundWorker跨執行緒對控件做控制。