Using Background worker class to do your work in separate thread :-
First we need to include System.ComponentModel namespace-
Imports System.ComponentModel
Now we need to do some declarations-
Dim WithEvents worker As New BackgroundWorker
Dim ListBox1 As New ListBox
Dim Button1 As New Button
Dim ProgressBar1 As New ProgressBar
Lets initialize these things and add them in our form so we get ready to go..
Just paste this code-
Private Sub buildForm()
With Me
.Size = New Size(350, 350)
End With
With ListBox1
.Size = New Size(300, 250)
.Location = New Point(10, 10)
End With
With ProgressBar1
.Size = New Size(215, 25)
.Location = New Point(10, 260)
.Maximum = 20
.Step = 1
End With
With Button1
.Size = New Size(75, 25)
.Location = New Point(235, 260)
.Text = "Go"
End With
Me.Controls.Add(ListBox1)
Me.Controls.Add(Button1)
Me.Controls.Add(ProgressBar1)
worker.WorkerReportsProgress = True
worker.WorkerSupportsCancellation = True
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
buildForm()
End Sub
Thats enough time spent on Form, lets move to the BackgroundWorker.
What we want to accomplist here is to Add number 1 to 20 in listbox1 on button click. and for some reason I want to do it in background thread.
Background worker has a DoWork event. When you call BackgroundWorker.RunWorkerAsync() method, a subroutine that handles DoWork event of BackgroundWoker is fired.
That means we need a sub routine that will have some work to do. Lets make it-
Private Sub worker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles worker.DoWork
For i = 0 To 20
ListBox1.Items.Add(i.ToString)
Thread.Sleep(100)
Next
End Sub
There’s it. Now if we call worker.RunWorkerAsync() in button1.Click, it should fire this event.
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
worker.RunWorkerAsync()
End Sub
Paste it and press F5 key to start debugging your application. After clicking a button, you’ll get InvalidOperationException at ListBox1.Items.Add(i.ToString) line.
Reason being our try to access controls created by/on different thread. Why this is invalid ? Because it can create a conflict ! In very simple words, nowadays we have dual core processors which can handle 2 threads at a time. If both the threads try to access same control at the same time, there’s a clash. Now, how to handle this exception or rather how to avoid this exception.. and there’re 2 ways to get rid of this.
First is to simply set Control.CheckForIllegalThreadCalls=False. Which is NOT RECOMMENDED. and other is to use Delegates to invoke methods.
Lets start with delegates. Declare a delegate sub.
Private Delegate Sub addItem(ByVal value As Integer)
We also need a subroutine that will add number in ListBox1.
Private Sub addListBoxItems(ByVal value As Integer)
ListBox1.Items.Add(value.ToString)
End Sub
Now we need to change our worker_DoWork() subroutine. We need to invoke method of Listbox1 using the delegate we have decalred.
This is how our modified code should be like-
Private Sub worker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles worker.DoWork
For i = 0 To 20
If ListBox1.InvokeRequired Then
ListBox1.Invoke(New addItem(AddressOf addListBoxItem), New Object() {i})
Else
ListBox1.Items.Add(i.ToString)
End If
Thread.Sleep(100)
Next
End Sub
Paste the code and check if it works fine. It does
Now we need to know progress of our background worker. Background worker class performs a ProgressChanged event as soon as we it reports progress. Write a sub routine that will handle progress changed event of our worker. We also need to check for progress and perform step of progress bar.
Private Sub worker_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles worker.ProgressChanged
ProgressBar1.PerformStep()
End Sub
This event will get fired when we worker reports progress. For that we need to put this line just before Next statement of for loop in worker_DoWork sub routine.
worker.ReportProgress(1)
We can also report value of loop variable ‘i’ in this context
worker.ReportProgress(i)
Hence, our worker_DoWork() sub routine will now look like this-
Private Sub worker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles worker.DoWork
For i = 0 To 20
If ListBox1.InvokeRequired Then
ListBox1.Invoke(New addItem(AddressOf addListBoxItem), New Object() {i})
Else
ListBox1.Items.Add(i.ToString)
End If
worker.ReportProgress(i)
Thread.Sleep(100)
Next
End Sub
Start debugging to see the effect !
and here’s our final complete code for reference-
Imports System.ComponentModel
Public Class Form1
Dim WithEvents worker As New BackgroundWorker
Dim ListBox1 As New ListBox
Dim WithEvents Button1 As New Button
Dim ProgressBar1 As New ProgressBar
Private Sub buildForm()
With Me
.Size = New Size(350, 350)
End With
With ListBox1
.Size = New Size(300, 250)
.Location = New Point(10, 10)
End With
With ProgressBar1
.Size = New Size(215, 25)
.Location = New Point(10, 260)
.Maximum = 20
.Step = 1
End With
With Button1
.Size = New Size(75, 25)
.Location = New Point(235, 260)
.Text = "Go"
End With
Me.Controls.Add(ListBox1)
Me.Controls.Add(Button1)
Me.Controls.Add(ProgressBar1)
worker.WorkerReportsProgress = True
worker.WorkerSupportsCancellation = True
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
buildForm()
Control.CheckForIllegalCrossThreadCalls = False
End Sub
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
worker.RunWorkerAsync()
End Sub
Private Delegate Sub addItem(ByVal value As Integer)
Private Sub addListBoxItem(ByVal value As Integer)
ListBox1.Items.Add(value.ToString)
End Sub
Private Sub worker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles worker.DoWork
For i = 0 To 20
If ListBox1.InvokeRequired Then
ListBox1.Invoke(New addItem(AddressOf addListBoxItem), New Object() {i})
Else
ListBox1.Items.Add(i.ToString)
End If
worker.ReportProgress(i)
Thread.Sleep(500)
Next
End Sub
Private Sub worker_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles worker.ProgressChanged
ProgressBar1.PerformStep()
End Sub
End Class
Thanks










[...] like report progress event. When using threads you need to apply somewhat similar logic. Refer my post about Background Workers to know more about it. In this post I’ll explain using threads for doing a similar task as [...]