在 window form 的程式,有些功能可能會需要執行一小段時間才能得到結果,在這段執行期間程式是陷於無回應(Hang住)。那該怎麼處理呢?就讓我們用 Backgroundworker 來將執行的程式片段放到背景去執行,並使用 Progressbar 來顯示整體的完成百分比。

--- 需要元件 ---
Backgroundworker:將工作丟到背景執行

Progressbar:顯示工作的完成度 

--- 參數設定 ---

Backgrou ndworker 的 
WorkerReportsProcess : Whether the worker will report progress.(回報執行進度)
WorkerSupportsCancellation: Whether the worker supports cancellation.(支援中途取消執行動作)

 ProgressBar 預設不顯示 ProgressBar1.Visible = False



--- 事件執行程序 ---

-1. 點選按鈕「btn_dojob」呼叫「BackgroundWorker1.RunWorkerAsync() 」開始背景執行程式

-2. 執行「BackgroundWorker1_DoWork」並於其中執行「 todo_work(worker, e)」,todo_work 是我們要丟到背景去執行的程式片段。

-3. 當第一次 todo_work 執行完成時,會呼叫「worker.ReportProgress」回報執行完成度與執行「BackgroundWorker1_ProgressChanged」更新顯示完成百分比。

若有 UI (User Interface)事件要顯示,必須在BackgroundWorker1_ProgressChanged中去處理,不能在程式執行片段 todo_work()中去表示。todo_work 當然更不能有跟使用者互動的動作,如msgbox()之類。

-4. 都執行完成後(100%),會去執行事件「BackgroundWorker1_RunWorkerCompleted」。

-A1. 取消時的動作程序
當設計一個按鈕要來中段背景執行的 process 時,可以呼叫「
Me.BackgroundWorker1.CancelAsync()」來達成中斷的目的。

-A2. 避免重複背景執行
在「執行按鈕」用
 BackgroundWorker1.IsBusy 判斷

-A3. 避免執行「取消」後繼續執行背景程式
在「todo_work」中用 
worker.CancellationPending 判斷,True 表示已執行取消。

--- 執行事件 ---

-1. 2個按鈕,分別為執行與取消

「執行按鈕」

 

Private Sub btn_dojob_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handlesbtn_dojob.Click

  If BackgroundWorker1.IsBusy Then

     MessageBox.Show("系統執行中")

  Else

     ProgressBar1.Visible = True

     BackgroundWorker1.RunWorkerAsync()  '起始背景執行的呼叫

  End If

End Sub

 

「取消按鈕」

 

Private Sub btn_cancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handlesbtn_cancel.Click

  If MsgBox("是否取消?" & vbCrLf & "在未按下ok前,系統仍會持續執行!", vbOKCancel, "是否中段執行") = MsgBoxResult.Ok Then

     Me.BackgroundWorker1.CancelAsync()

  End If

End Sub

 

-2. 準備執行的程式片段 todo_work()

 

Private Sub todo_work(ByVal worker As BackgroundWorker, ByVal e As DoWorkEventArgs)

   If worker.CancellationPending Then

       e.Cancel = True

   Else
    
  For k = 1 To numberToCompute

       If My.Computer.Network.Ping(Server_List) Then 

         server_ping = ok

       Else

         server_ping = bad

       End If

percentComplete = CInt((k / numberToCompute) * 100)

              worker.ReportProgress(percentComplete)  回報完成率

     Next
    End If  

End Sub

 

-3. Backgroundworker 事件處理

 

Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e AsSystem.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

要使用 baclgroundWorker  Imports System.ComponentModel

   Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)

   todo_work(worker, e)   '欲背景執行的 function

End Sub

 

Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As System.Object, ByVal e AsSystem.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged

   Me.ProgressBar1.Value = e.ProgressPercentage

更新 ProgressBar1 的百分比值

End Sub

 

Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e AsSystem.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted

   If (e.Error IsNot NothingThen

       MessageBox.Show(e.Error.Message)

   ElseIf e.Cancelled Then

       MessageBox.Show("使用者取消執行!")

   Else

       ProgressBar1.Visible = False   執行完成隱藏 ProgressBar

       MessageBox.Show("工作完成!")

   End If

End Sub

 

-4. 如果想要知道程式執行是否持續執行沒被hang住,可以加入 timer 顯示來做為判斷

 

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

   Label2.Text = Now.ToString("HH:mm:ss.ffffff")

   ' Label2.Text = Format(Now(), "yy:mm:dd HH:mm:ss.ff")

End Sub

 

-5. 換你試試看囉!

Reference:

  • http://msdn.microsoft.com/zh-tw/library/8xs8549b%28VS.80%29.aspx 
  • http://msdn.microsoft.com/zh-tw/library/hybbz6ke%28v=VS.80%29.aspx
  • Backgroundwork 圖:http://images.cnblogs.com/cnblogs_com/happy555/backgroundworker.jpg
  • http://msdn.microsoft.com/zh-tw/library/bd6xat66%28v=VS.95%29.aspx