How To Update Controls Using BackgroundWorker in VB.NET
September 24th, 2007
The .NET Framework 2.0 BackgroundWorker class makes it easy to code simple threading into your applications. However, a common question that gets asked in VB related forums is, “How do I update a control, or controls, from the worker thread?”. Many people seem to be in search of a simple explanation of how to do this. In this article we’ll create a quick and easy example program that will walk you through the steps.
Getting Started
First, we will need to create a new Windows application. On our form we’ll add two buttons, btnStart and btnCancel, a progress bar, prgThread, and a listbox, lstValues. You may also want to import System.ComponentModel into the project namespace or onto the form or you can just spell it out like I’m doing below.
Next we’re going to add code. First, we declare the BackgroundWorker object, TestWorker. Note that we’re declaring it with events so that the event structure is built automatically.
' Private WithEvents TestWorker As System.ComponentModel.BackgroundWorker ' '
Now, code is added for the start button, btnStart.
Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click btnStart.Enabled = False btnCancel.Enabled = True lstValues.Items.Clear() prgThread.Value = 0 TestWorker = New System.ComponentModel.BackgroundWorker TestWorker.WorkerReportsProgress = True TestWorker.WorkerSupportsCancellation = True TestWorker.RunWorkerAsync() End Sub
First, we disable the start button and enable the cancel button. Next we reset the values for our listbox and and progressbar. Now we’re ready to create our BackgroundWorker object. Notice that we tell it that we want to have it report progress and support cancellation. Finally, we tell it to run the worker.
The Worker
Here’s the code for our worker thread. This code is contained in the DoWork event. All it’s doing is looping 100 times and reporting the progress and sleeping 100ms between iterations. We also check for a cancellation state.
Private Sub TestWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles TestWorker.DoWork Dim ListText As String For Value As Integer = 0 To 100 If TestWorker.CancellationPending Then Exit For End If ListText = String.Concat("Item #", Value) TestWorker.ReportProgress(Value, ListText) Threading.Thread.Sleep(100) Next End Sub
You can also see that in the ReportProgress function call that we’re passing in the current value and a string.
Updating Form Controls
In the ProgressChanged event, we get to process our values from our DoWork method. Here’s the code:
Private Sub TestWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles TestWorker.ProgressChanged prgThread.Value = e.ProgressPercentage lstValues.Items.Add(e.UserState) End Sub '
In this routine, the progress bar and the listbox are updated with values from the worker thread. Remember that the UserState value is an object and will require conversion if you can’t use an object type.
Canceling the Worker
Now, what if you want to cancel the worker? Here’s the code that goes into our cancel button’s Click event:
Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click TestWorker.CancelAsync() End Sub ' '
Here we call the CancelAsync method. However, this only sets a flag and, as shown above, our DoWork method has to check for a CancellationPending state. Otherwise, the work will continue until the DoWork routine is exited.
Finishing Things Up
When the work has been completed or canceled, the RunWorkerCompleted method is called. In our program, this allows us to reset our buttons.
Private Sub TestWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles TestWorker.RunWorkerCompleted btnStart.Enabled = True btnCancel.Enabled = False End Sub
That’s how it’s done in a nutshell. Of course, handling multi-threading in your applications can become very tricky. It is recommended that you further review how to avoid problems with threading before implementing it.
Let me know if you have any questions about BackgroundWorker or if you have any suggestions or thoughts about this example by leaving me a comment.
Entry Filed under: Code Examples, VB.NET Tutorials
Rate This Article:









(23 votes, average: 4.74 out of 5)
23 Comments Add your own
1. David | October 3rd, 2007 at 1:42 pm
Nice post. Wish thi had been up when I was learning BW. :(
Question for you. Are you aware of anyway to pass mor than 2 events to the progress handler? I’m needing to update 3 or more fields and currently I cannot do so without using another BW. Thanks in advance.
2. jfrankcarr | October 3rd, 2007 at 2:16 pm
Thanks David
The way to do this would be to use a class (or structure) for your updates rather than just using a String as in the example above. For example, let’s say that I want to pass a user name, user ID, and email address back from the worker thread. I would create a class like this:
And in the worker DoWork I would create the object and use it in the second parameter:
CurrentUser = New WorkerUser(CurrentUserName, CurrentUserId, CurrentEmailAddress) TestWorker.ReportProgress(value, CurrentUser)Then in the ProgressChanged event I would break out the values as needed.
I hope this is what you were looking for.
3. Duane Scherzinger | December 15th, 2007 at 7:49 pm
I have a question about using the backgroundworker. I have a form that is using a datagridview to display/edit some data. The data is stored in a dataset. I want to load the dataset while also starting the paint routine to display the form. I have the background worker running on the support object for the form (not the form itself) The dataset will fill with the correct data, but does not display. The datagridview has a rowcount of 0 while the dataset has a rowcount of 35 (correct number). The dataset is assigned as the datagridview’s datasource and the table within the dataset is assigned as the datagridview’s datamember. What is happening. If I remove the backgrounder worker logic and just let the dataset befilled as part of the form’s load event then all works. Can you offer me any help.
Thank you for your time and information
Duane
4. Lucas | January 21st, 2008 at 6:44 pm
Thank you for posting this!
I had written a very simple example to teach myself how to use the BW but my Cancel button would never stop the loop in the DoWork event. Now I know why: You have to have the Threading.Thread.Sleep line in the loop or the BW.CancellationPending condition check will be blissfully ignored. Comment out the Sleep line, extend the duration of the loop to give yourself enough time and try to press the Cancel button. It won’t work. Is it expected behavior?
5. Venkata | February 20th, 2008 at 9:28 am
Great Article for Beginers.
6. Andrew | May 14th, 2008 at 5:00 pm
I’m having a terrible time with the backgroundworker control.
Here’s the scenario:
I have a form with a DataGridView on it which I want to be updated by a Backgroundworker.
I have a separate module that has an event-driven handler that calls RunWorkerAsync.
If I declare the BackGroundWorker (and the DoWork and RunWorkerCompleted Subs) in the Form, the RunWorkerCompleted event never fires.
If I declare the BackGroundWorker (and DoWork and RunWorkerCompleted Subs) in the separate module where the RunWorkerAsync command is called, the RunWorkerCompleted event does fire, but inside that sub is the code to update the DataGridView, and I get an error saying that I cannot update the DataGridView from a thread other than the one the DataGridView is on.
I don’t want to have all the code that’s in my module stuck in the Form’s code as the classes in the module get used elsewhere as well.
I’ve tried everything I can think of, searched the internet for days and I simply cannot figure out how to get this to work.
I even gave up on using BackgroundWorker but within the separate module I cannot update the DataGridView. It seems it can only be updated from within the form’s code that the DataGridView is on.
Augh! Help? Please?
If I declare the BackGroundWorker
7. Ricky | May 21st, 2008 at 10:59 am
Firstly, thankyou jfrankcarr. Helped me out. I can now update many controls, previously I only passed information through the userstate.
Andrew, can you paste your code so we can look?
8. DavidM | June 3rd, 2008 at 4:30 pm
Can this BW be used on webapps to create a progressbar for uploading files. Where the BW returns ProgressPercentage and gives it back to an Ajax request?
Tell me if i’m completely off track.
Thanks
9. LloydM | August 8th, 2008 at 2:59 pm
Thanks
This article pushed me over the top of the hill
I integrated the concept with the way i was already using events for a progress bar in wpf and .net 3.5. Now the progress bar is real time.
Thanks Again
LM AKA DkUltra
10. FSReyes | September 11th, 2008 at 4:06 pm
Just to say thanks. You make it so simple than other examples out there.
Now I got my progress bar working with a call on my stored procedure. I got the progress bar to work like KITT in Knight Rider until when it encounters the RunWorkerCompleted.
11. djib | October 16th, 2008 at 9:39 am
Hello,
Thanks for that post.
I’m still having quit a bit of trouble with threading though. Here is my problem :
I have an application running a TCPListener in a Thread. I created a Logger singleton that can display text in a TextBox.
The thing is that both my TCPListener and my main thread need to access the Logger.
The problem is that when I access the Logger via the TCPListener, it won’t allow me to update the control on the form. I can’t figure out how to get it to work.
Thanks for your help.
12. djib | October 16th, 2008 at 10:36 am
Mmmh, sorry for the trouble… I just found a solution using a Delegate !
Public Class LogWindow
Implements ILogWindow
Public Delegate Sub DelegateLog(ByVal text As String)
Public Sub log(ByVal text As String) Implements ILogWindow.log
If Me.InvokeRequired Then
Me.Invoke(New DelegateLog(AddressOf Me.log), New Object() {text})
Else
Me.LogBox.Text += text
End If
End Sub
End Class
13. James | October 18th, 2008 at 12:36 am
I almost gave up on the progress bar. I would have a long time ago but my programs were too unstable. Thanks to your examples I have everything working great.
14. sivakumarm | November 6th, 2008 at 7:43 am
i had look on backgroudworker, i is very nice
but i have one doubt, i am using threads to get asynchronous call to worker procedure…but it is working fine, for normal query “insert” but same scripts i am just running in stored procedure that time, after getting right result, my application not responding to select any option in UI.
can you make any comments reg. the same
sivam
15. ALegaspi | November 14th, 2008 at 11:59 am
THank you for this article… this gives me idea how to use the BW.
But I have a question. I have a situation that I think but Im not sure backgroundworker will help solve this problem. I have a form that contains all th details of our product and wthin this form I have a button that when you click it will popup another form let say sub form for the user to select a product. within this sub form I have to button “select” and “Add” button. When I click select it will add my selections let say on a collection to hold the data. and Add button will works to add another selection. What I want is to update the main form that contains the details of what I select from sub form. Right now on how it works, the details or data will only be displayed on the main form after clicking the ok button. What I want is updating the mainform to show my selections everytime i click select or add button. Do you think backgroundworker will help me on this? fi not do you have any suggestions of what is better to do on this? thanks it will really helps me a lot when I solve this problem.
16. BJ452 | December 24th, 2008 at 4:43 am
As a neby I have been searhing for a simple, easy to understand demonstration of multithreadng and found this to be the most useful - Mnay examples only show snippets - and assume you know where to put them. what to import etc. Nice job - I will look out for more articles by you - thanks
17. Bea | January 21st, 2009 at 1:42 pm
I’m trying to get my toolstripprogressbar to run at the same time my SQLDataReader and Datagridview is loading. The toolstripprogressbar runs after the datagridview loads. I’ve followed your example, also tried building a seperate thread with invokes and callbacks. The progressbar just does not seem to want to run while the datagridview is loading(which takes some time). Can I send my code to you? Thanks.
18. confused with threads - i&hellip | February 17th, 2009 at 1:22 pm
[...] How To Update Controls Using BackgroundWorker in VB.NET This article was insightful and simple to follow when I was learning about the BackgroundWorker. [...]
19. Bart | February 21st, 2009 at 4:08 pm
Hi,
I tried to use your example but somehow it doesn’t work. After TestWorker.RunWorkerAsync(), in stead of going to Private Sub TestWorker_DoWork, my program directly goes to: Private Sub TestWorker_RunWorkerCompleted, bypassing the important part of the code this way.
I wrote the code in the form and then tried to place the backgroundworker control on the form, but I couldn’t rename it to the name used in the code, as it already existed. Could this have anything to do with this and should I create the object on the form first and only then write the code?
I’m using VS2008 Express.
Any suggestions?
Bart
20. Bart | February 23rd, 2009 at 8:04 am
Hi again,
I already found out what went wrong. It was a faulty value assignment to the To variable in the For…To loop. Pretty stupid…
But this is a great tutorial, it really helped me show the way!
Thanks,
Bart
21. Mark-C | June 9th, 2009 at 2:00 pm
Hi, thanks, I wish I hhad found this sooner !
Many comments seem to share my problem of sharing data between forms and threads.
I have found that using variables (structures) declared at module level helps. Is this bad practice or a reasonable solution?
Cheers
22. Tony | June 22nd, 2009 at 11:57 am
Thanks for the great beginners article on BackgroundWorkers! Very insightful.
23. Paul B | September 27th, 2009 at 5:16 am
Hi, I am a bit of a beginner when it comes to threads, but this article has helped me. Thank you.
What I need to know now is how do I pass values to the backround worker.
eg. In the original artical I would like the user to be able to set the start and end values of the loop.
Leave a Comment
Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
Trackback this post | Subscribe to the comments via RSS Feed