比如連上網路下載或上傳東西
但在和網路溝通及傳輸的時候,畫面上的工作就會暫停
這時候會想要提示使用者程式還在工作,比如說在msn登入的時候撥放動畫
這時候就要用到背景工作了,實際上這就是一種多執行緒處理
只是.net提供了方便的包裝,讓主執行緒在背景工作執行中得知進度
BackgroundWorker主要有三個事件處理
| 事件 | 說明 | 
|---|---|
| DoWork | 在背景執行的工作,為另外一個執行緒,不可以變更介面畫面(介面變更在後面兩個事件中處理) | 
| RunWorkerCompleted | 背景工作完成後的處理,因為背景工作是非同步處理,所以在完成後會觸發這事件來啟動主執行緒接下來的動作,如登入完成後執行切換畫面 | 
| ProgressChanged | 如果動作費時太長,有時候會希望將進度反應在介面上,在這裡改變介面畫面 | 
我們來做一個範例(參考HOW TO:使用幕後背景工作)
視窗中只有一個按鈕(Button)
<Window ...>
    <Button Name="b" Click="Button_Click" />
</Window>
在按鈕按下的時候開始設定並執行背景工作
private void Button_Click(
    object sender, RoutedEventArgs e)
{
    /// new and allow cancel and report progress 
    BackgroundWorker bw = new BackgroundWorker();
    bw.WorkerSupportsCancellation = true;
    bw.WorkerReportsProgress = true;
    /// add the event handler for each progress 
    bw.DoWork += new DoWorkEventHandler(DoWork);
    bw.ProgressChanged +=
        new ProgressChangedEventHandler(DuringWork);
    bw.RunWorkerCompleted +=
        new RunWorkerCompletedEventHandler(AfterWork);
    /// start the background work 
    bw.RunWorkerAsync();
}
事件處理定義如下
void DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker w = sender as BackgroundWorker;
    for (int i = 1; i <= 10; i++)
    {
        /// check if the work is cancelled 
        if (w.CancellationPending == true)
        {
            e.Cancel = true;
            break;
        }
        /// perform a time consuming operation 
        Thread.Sleep(500);
        /// report progress in percentage 
        w.ReportProgress(i * 10);
    }
}
void DuringWork(
    object sender, ProgressChangedEventArgs e)
{
    /// reflect the change of progress in UI 
    b.Content =
        e.ProgressPercentage.ToString() + "%";
}
void AfterWork(
    object sender, RunWorkerCompletedEventArgs e)
{
    /// reflect the result after background work 
    if (e.Cancelled == true)
    {
        b.Content = "Canceled!";
    }
    else if (!(e.Error == null))
    {
        b.Content = ("Error: " + e.Error.Message);
    }
    else
    {
        b.Content = "Done!";
    }
}
這個程式執行後,按下按鈕的時候
就會開始執行DoWork裡面的動作(每半秒更新一下進度)
並在每次更新進度的時候更新Button上面顯示的文字
另外,有時候背景程式需要使用到介面輸入的資訊
(比如登入畫面,需要將帳號密碼傳上網路)
但是DoWork裡面不能使用介面的物件
這時候可以透過argument(object形態,可以傳任意型別)傳入
所以啟動背景工作的呼叫改寫成
private void Button_Click(
    object sender, RoutedEventArgs e)
{
    /// new and allow cancel and report progress 
    BackgroundWorker bw = new BackgroundWorker();
    bw.WorkerSupportsCancellation = true;
    bw.WorkerReportsProgress = true;
    /// add the event handler for each progress 
    bw.DoWork += new DoWorkEventHandler(DoWork);
    bw.ProgressChanged +=
        new ProgressChangedEventHandler(DuringWork);
    bw.RunWorkerCompleted +=
        new RunWorkerCompletedEventHandler(AfterWork);
    /// start the background work with argument 
    bw.RunWorkerAsync(b.Content );
}
而在DoWork裡面則是用e.Argument將傳入的參數讀出
如果有超過一個以上的參數,也可以利用ArrayList先打包起來再一起傳
--
參考資料
HOW TO:使用幕後背景工作
BackgroundWorker 類別

沒有留言:
張貼留言