The Background WorkerWhat is a background worker?A background worker allow the designer to offload some of processing on another thread, which can make the UI feel more responsive.
How to use a background worker.For this demonstration you'll have to create a new windows application project, until you grasped the basics.
Add two buttons to the form, name them Start_Button & Stop_Button
Add a progress bar
Add a label, named lbl_Status
Add a Background worker.
Set then enable state of the stop button to False
In the properties of the background worker set the following properties to true.
WorkerSupportsCancellation & WorkerReportsProgress
Now view to code of the form and add the following code the top.
CODE
Dim m_CountTo As Integer = 0' How many time to loop.
Double Click on the start button and enter.
CODE
Private Sub Start_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Start_Button.Click
'Set the count to 30
m_CountTo = 30
' Disable the start button
Me.Start_Button.Enabled = False
' Enable to stop button
Me.Stop_Button.Enabled = True
' Start the Background Worker working
My_BgWorker.RunWorkerAsync()
End Sub
Double Click the stop button
CODE
Private Sub Stop_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Stop_Button.Click
' Is the Background Worker do some work?
If My_BgWorker.IsBusy Then
'If it supports cancellation, Cancel It
If My_BgWorker.WorkerSupportsCancellation Then
' Tell the Background Worker to stop working.
My_BgWorker.CancelAsync()
End If
End If
' Enable to Start Button
Me.Start_Button.Enabled = True
' Disable to Stop Button
Me.Stop_Button.Enabled = False
End Sub
Then Next section of code is the code that is to be run in the background.
CODE
Private Sub My_BgWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles My_BgWorker.DoWork
For i As Integer = 0 To m_CountTo
' Has the background worker be told to stop?
If My_BgWorker.CancellationPending Then
' Set Cancel to True
e.Cancel = True
Exit For
End If
System.Threading.Thread.Sleep(1000) ' Sleep for 1 Second
' Report The progress of the Background Worker.
My_BgWorker.ReportProgress(CInt((i / m_CountTo) * 100))
Next
End Sub
Note: That the
My_BgWorker.ReportProgress only excepts integer values between 0 to 100 inclusive. So you'll have to scale your value to this range.
Now to add the code to update the Progress Bar
CODE
Private Sub My_BgWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles My_BgWorker.ProgressChanged
' Update the progress bar
Me.ProgressBar1.Value = e.ProgressPercentage
End Sub
Now for the code that runs after the Background Worker is finished.
CODE
Private Sub My_BgWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles My_BgWorker.RunWorkerCompleted
If e.Cancelled Then
Me.Lbl_Status.Text = "Cancelled"
Else
Me.Lbl_Status.Text = "Completed"
End If
End Sub
Now that all it takes to use a Background Worker.
For the more adventurous of youLet's use that label and display a percentage of completion.
Add this extra line of code to the DoWork procedure
CODE
My_BgWorker.ReportProgress(CInt((i / m_CountTo) * 100))
Me.Lbl_Status.Text = FormatPercent(i / m_CountTo, 2) ' Show Percentage in Label
And Run.
You get the following error
Cross-thread operation not valid: Control 'Lbl_Status' accessed from a thread other than the thread it was created on.Why?Because we are using a background worker and we're attempting to access controls on a different thread (The UI or form).
VB.Net doesn't like use talking to objects on another thread directly, so have to go Indirectly through a intermediary called a Delegate
It is possible to turn it off and allow them but that's just asking for trouble. I'll show you the proper and correct way to achieve this, by adding a new subroutine and a delegate.
A delegate helps to communicate to objects of a different thread;- It delegates the talking between the different threads.
Go back to the code and enter the following code.
CODE
' The delegate
Delegate Sub SetLabelText_Delegate(ByVal [Label] As Label, ByVal [text] As String)
' The delegates subroutine.
Private Sub SetLabelText_ThreadSafe(ByVal [Label] As Label, ByVal [text] As String)
' InvokeRequired required compares the thread ID of the calling thread to the thread ID of the creating thread.
' If these threads are different, it returns true.
If [Label].InvokeRequired Then
Dim MyDelegate As New SetLabelText_Delegate(AddressOf SetLabelText_ThreadSafe)
Me.Invoke(MyDelegate, New Object() {[Label], [text]})
Else
[Label].Text = [text]
End If
End Sub
To use comment out the line code in Do Work routine that caused the error, then enter the following.
CODE
My_BgWorker.ReportProgress(CInt((i / m_CountTo) * 100))
' Me.Lbl_Status.Text = FormatPercent(i / m_CountTo, 2)
SetLabelText_ThreadSafe(Me.Lbl_Status, FormatPercent(i / m_CountTo, 2))
And run, now you have the label displaying the percentage.
Now you have the Background Worker in your Code Ninja arsenal.
