7 Ways To Hire Smarter Programmers3 Handy VB.NET File Functions You Can Use

How To Update Controls Using BackgroundWorker in VB.NET

September 24th, 2007

BackgroundWorker Paints a FormThe .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.

Share This Article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • DotNetKicks
  • DZone

Entry Filed under: Code Examples, VB.NET Tutorials


Rate This Article:

Not That GoodCould Be BetterOKGoodGreat (37 votes, average: 4.76 out of 5)
Loading ... Loading ...

24 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:

    Private Class WorkerUser
        Public UserName As String
        Public UserID As Integer
        Public EmailAddress As String
    
        Public Sub New(ByVal uName As String, ByVal uID As Integer, ByVal email As String)
            UserName = uName
            UserID = uID
            EmailAddress = email
        End Sub
    End Class

    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.

    Private Sub TestWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles TestWorker.ProgressChanged
        prgThread.Value = e.ProgressPercentage
        Dim CurrentUser As WorkerUser = DirectCast(e.UserState, WorkerUser)
        lstUsers.Items.Add(CurrentUser.UserName)
        lstEmails.Items.Add(CurrentUser.EmailAddress)
        IdList.Add(CurrentUser.UserID)
    End Sub

    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.

  • 24. Eric  |  December 23rd, 2009 at 11:07 am

    Excellent. This is exaclty what I was looking for to smooth out some of my applications.

Leave a Comment

Required

Required, hidden

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


Visit Me At My New Site, Programming In C#

Most Popular Articles

Highest Rated Articles

Categories

Most Recent Articles

Feeds

 Subscribe in a reader

To subscribe by e-mail
Enter your address here

Delivered by FeedBurner

VB Opportunities

Archives