實戰.Net多執行緒(三)

草上爬發表於2008-08-13
BackgroundWorker類在 .NET Framework 2.0 中是新增的,它能夠在單獨的執行緒上執行特定操作。

關於BackgroundWorker的基本使用方法我們不在這裡說明,在MSDN中已經有了很詳細的介紹,並且還有個關於如何使用 BackgroundWorker 類非同步執行耗時操作的示例,該示例是計算選定的斐波納契數、在計算過程中報告進度更新,並允許取消掛起的計算等。這個例子很基礎:在主窗體中有兩個button,一個用於啟動BackgroundWorker的執行,另一個用於取消,而進度條指示是在主窗體上顯示,縱觀這個示例並不是特別適用於實際使用。而我們則需要更多的功能,並且製作出接近實際使用的示例!

我們的目標有兩個,1、啟動和終止執行緒要在一個button內完成;2、需要在另一個單獨的窗體中顯示耗時操作的進度。解決第一個問題需要在button單擊事件需要判斷BackgroundWorker類的例項是否已建立,然後需要檢測BackgroundWorker的一個屬性IsBusy,當IsBusy=true時說明BackgroundWorker正在後臺進行處理,否則可以重新開始一個後臺操作,程式碼如下:

        private BackgroundWorker m_AsyncWorker1 = null;
        private void button4_Click(object sender, EventArgs e)
        {
            if (m_AsyncWorker1 == null)
            {
                m_AsyncWorker1 = new BackgroundWorker();
                m_AsyncWorker1.WorkerReportsProgress = true;
                m_AsyncWorker1.WorkerSupportsCancellation = true;
                m_AsyncWorker1.ProgressChanged += new ProgressChangedEventHandler(m_AsyncWorker1_ProgressChanged);
                m_AsyncWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_AsyncWorker1_RunWorkerCompleted);
                m_AsyncWorker1.DoWork += new DoWorkEventHandler(m_AsyncWorker1_DoWork);
            }
            if (m_AsyncWorker1.IsBusy)
            {
                button4.Enabled = false;
                button4.Text = "Canceling, Please wait....";
                m_AsyncWorker1.CancelAsync();
            }
            else
            {
                button4.Text = "Cancel";
                m_AsyncWorker1.RunWorkerAsync();
            }
        }

我們的示例是建立一個隨機數,然後從0開始遍歷這個隨機數,並且通過在主窗體上的Label和ProgressBar呈現出迴圈的進度。

ProgressChanged、RunWorkerCompleted和DoWork是BackgroundWorker的最重要的事件,我們可以按照方法指標型別來對待它,因為其實它就是一個委託型別,為了驗證DoWork是委託型別,有一個最簡單方法,就是在IDE的文字編輯器中的DoWork上右鍵"轉到定義",這時會看到DoWork是DoWorkEventHandler型別的事件,這當然沒錯!然後繼續在DoWorkEventHandler上右鍵"轉到定義",這時我們就會經意的發現:

public delegate void DoWorkEventHandler(object sender, DoWorkEventArgs e);

原來事件的基本形態還是委託!所以在 .Net 下事件和委託是不可分割的兩種型別!!過一段時間我會特別寫博文來和大家一起專門試驗和探討.Net事件和委託。

知道了是方法指標型別,我們就可以按照地址的形式賦予DoWork事件被激發時需要執行的操作的方法地址,亦即:

m_AsyncWorker1.DoWork += new DoWorkEventHandler(m_AsyncWorker1_DoWork);

好了,扯得稍微有點遠了。我們繼續看ProgressChanged、RunWorkerCompleted和DoWork的實際內容,程式碼如下:

        private void m_AsyncWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bwAsync = sender as BackgroundWorker;
            int iCount = new Random().Next(20, 50);
            for (int i = 0; i < iCount; i++)
            {
                Thread.Sleep(100);
                bwAsync.ReportProgress(Convert.ToInt32(i * (100.0 / iCount)));
                if (bwAsync.CancellationPending)
                {
                    Thread.Sleep(1200);
                    e.Cancel = true;
                    return;
                }
            }
            bwAsync.ReportProgress(100);
        }

        private void m_AsyncWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
            label1.Text = e.ProgressPercentage.ToString() + "%";
        }

        private void m_AsyncWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            button4.Text = "Start";
            progressBar1.Value = 0;
            button4.Enabled = true;
            if (e.Error != null)
            {
                MessageBox.Show(this, e.Error.Message);
                return;
            }
            if (e.Cancelled)
            {
                //Cancelled...
            }
            else
            {
                //Completed...
            }
            m_AsyncWorker1 = null;
        }

在MSDN中關於取消後臺操作的程式碼過於基礎,不太利於實際使用。取消後臺操作大家都知道需要呼叫m_AsyncWorker1.CancelAsync(),而在DoWork遍歷數字的迴圈體內我們隨時檢測bwAsync.CancellationPending的狀態,若CancellationPending=true,說明使用者已經第二次單擊了button,亦即執行了m_AsyncWorker1.CancelAsync() ,這是需要告知BackgroundWorker準備中止操作,即e.Cancel=true。

不管是中途取消還是順利完成後臺操作,RunWorkerCompleted事件都要最後執行,所以在這段程式碼中必需檢測後臺操作是否已取消還是順利完成,然後新增相應的程式碼。

在下一篇博文中我們會繼續利用BackgroundWorker來建立更加專業的在獨立窗體中顯示後臺操作進度,以及終止後臺操作的示例。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14325734/viewspace-426849/,如需轉載,請註明出處,否則將追究法律責任。

相關文章