WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Understanding the BackgroundWorker Component
Pages: 1, 2

Let's switch to the code behind of the Windows form and do the coding. First, import the following namespace:




Imports System.ComponentModel

When the Start button is clicked, you first initialize some of the controls on the form. You also change the cursor to an hourglass (Cursors.WaitCursor) so that the user knows the application is working. You then get the BackgroundWorker component to spin off a separate thread using the RunWorkAsync() method. You pass the number entered by the user as the parameter for this method:


Private Sub btnStart_Click( _
   ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles btnStart.Click
    lblResult.Text = ""
    btnCancel.Enabled = True
    btnStart.Enabled = False
    ProgressBar1.Value = 0
    Me.Cursor = Cursors.WaitCursor

    BackgroundWorker1.RunWorkerAsync(txtNum.Text)
End Sub

The DoWork event of the BackgroundWorker component will invoke the SumNumbers() function (which I will define next) in a separate thread. This event (DoWork) is fired when you call the RunWorkerAsync() method (as was done in the previous step).


Private Sub BackgroundWorker1_DoWork( _
   ByVal sender As System.Object, _
   ByVal e As System.ComponentModel.DoWorkEventArgs) _
   Handles BackgroundWorker1.DoWork
    'This method will run on a thread other than the UI thread.
    'Be sure not to manipulate any Windows Forms controls created
    'on the UI thread from this method.
    Dim worker As System.ComponentModel.BackgroundWorker = _
       CType(sender, System.ComponentModel.BackgroundWorker)
    e.Result = SumNumbers(CType(e.Argument, Double), worker, e)
End Sub

The SumNumbers() function basically sums up all the numbers from 0 to the number specified. It takes in three arguments--the number to sum up to, the BackgroundWorker, and the DoWorkEventArgs. Note that within the For loop, you check to see if the user has clicked on the Cancel button (the event will be defined later in this article) by checking the value of the CancellationPending property. If the user has cancelled the process, set e.Cancel to True. For every ten iterations, I will also calculate the progress completed so far. If there is progress (when the current progress percentage is greater than the last one recorded), then I will update the progress bar by calling the ReportProgress() method of the BackgroundWorker component. You should not call the ReportProgress() method unnecessarily, as frequent calls to update the progress bar will freeze the UI of your application.

It is important that note that in this method (which was invoked by the DoWork event), you cannot directly access the Windows controls, as they are not thread-safe. Trying to do so will also trigger a runtime error, a useful feature new in Visual Studio 2005.


Function SumNumbers( _
   ByVal number As Double, _
   ByVal worker As System.ComponentModel.BackgroundWorker, _
   ByVal e As DoWorkEventArgs) As Double

  Dim lastPercent As Integer = 0
  Dim sum As Double = 0

  For i As Double = 0 To number
    '---check if user cancelled the process
    If worker.CancellationPending = True Then
      e.Cancel = True
    Else
      sum += i
      If i Mod 10 = 0 Then
        Dim percentDone As Integer = i / number * 100
        '---update the progress bar if there is a change
        If percentDone > lastPercent Then
          worker.ReportProgress(percentDone)
          lastPercent = percentDone
        End If
      End If
    End If
  Next
  Return sum
End Function

The ProgressChanged event is invoked whenever the ReportProgress() method is called. In this case, I used it to update my progress bar:


Private Sub backgroundWorker1_ProgressChanged( _
   ByVal sender As Object, ByVal e As ProgressChangedEventArgs) _
   Handles BackgroundWorker1.ProgressChanged
  '---updates the progress bar
  ProgressBar1.Value = e.ProgressPercentage
End Sub

The RunWorkerCompleted event is fired when the thread (SumNumbers(), in this case) has completed running. Here you will print the result accordingly and change the cursor back to the default:


Private Sub BackgroundWorker1_RunWorkerCompleted( _
   ByVal sender As Object, _
   ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
   Handles BackgroundWorker1.RunWorkerCompleted
  If Not (e.Error Is Nothing) Then
    MsgBox(e.Error.Message)
  ElseIf e.Cancelled Then
    MsgBox("Cancelled")
  Else
    lblResult.Text = "Sum of 1 to " & _
    txtNum.Text & " is " & e.Result
  End If
  btnStart.Enabled = True
  btnCancel.Enabled = False
  Me.Cursor = Cursors.Default
End Sub

Finally, when the user clicks the Cancel button, you cancel the process by calling the CancelAsync() method:


Private Sub btnCancel_Click( _
   ByVal sender As System.Object, _
   ByVal e As System.EventArgs) _
   Handles btnCancel.Click
	' Cancel the asynchronous operation.
	BackgroundWorker1.CancelAsync()
	btnCancel.Enabled = False
End Sub

Testing the Application

To test the application, press F5 and enter a large number (say, 9999999) and click the Start button. You should see the progress bar updating and the cursor changed to an hourglass. When the process is completed, the result will be printed in the Label control (see Figure 4).

figure 4
Figure 4. Testing the application

Wei-Meng Lee (Microsoft MVP) http://weimenglee.blogspot.com is a technologist and founder of Developer Learning Solutions http://www.developerlearningsolutions.com, a technology company specializing in hands-on training on the latest Microsoft technologies.


Return to the OnDotNet.com