Results 1 to 30 of 30

Thread: Correct way to use the BackgroundWorker

Threaded View

  1. #1

    Thread Starter
    VB Addict Pradeep1210's Avatar
    Join Date
    Apr 2004
    Location
    Inside the CPU...
    Posts
    6,614

    Correct way to use the BackgroundWorker

    I see forum members often getting confused and asking about how the background worker should be correctly coded.

    Without going into much of the theory, I will demonstrate it with the help of an example. Pay attention the the comments in the code for explanation about each part of the code.

    For this demo, put a BackgroundWorker, two Labels and two Buttons on your form. The default names (BackgroundWorker1, Label1, Label2, Button1, Button2) apply. Otherwise change appropriately in the code, or the names of the Controls.

    Then put the following code:
    vb.net Code:
    1. Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    2.     Button1.Text = "Start"
    3.     Button2.Text = "Cancel"
    4.     Label1.Text = ""
    5.     Label2.Text = ""
    6. End Sub
    7.  
    8. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    9.     Button1.Enabled = False
    10.     Button2.Enabled = True
    11.  
    12.     '' these properties should be set to True (at design-time or runtime) before calling the RunWorkerAsync
    13.     '' to ensure that it supports Cancellation and reporting Progress
    14.     BackgroundWorker1.WorkerSupportsCancellation = True
    15.     BackgroundWorker1.WorkerReportsProgress = True
    16.  
    17.     '' call this method to start your asynchronous Task.
    18.     BackgroundWorker1.RunWorkerAsync()
    19. End Sub
    20.  
    21. Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
    22.     '' to cancel the task, just call the BackgroundWorker1.CancelAsync method.
    23.     Button2.Enabled = False
    24.     BackgroundWorker1.CancelAsync()
    25. End Sub
    26.  
    27. Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    28.     '' The asynchronous task you want to perform goes here
    29.     '' the following is an example of how it typically goes.
    30.  
    31.     Const Max As Integer = 1000
    32.  
    33.     For i = 1 To Max
    34.         '' do something
    35.         '' (I put a sleep to simulate time consumed)
    36.         Threading.Thread.Sleep(100)
    37.  
    38.         '' report progress at regular intervals
    39.         BackgroundWorker1.ReportProgress(CInt(100 * i / Max), "Running..." & i.ToString)
    40.  
    41.         '' check at regular intervals for CancellationPending
    42.         If BackgroundWorker1.CancellationPending Then
    43.             BackgroundWorker1.ReportProgress(CInt(100 * i / Max), "Cancelling...")
    44.             Exit For
    45.         End If
    46.     Next
    47.  
    48.     '' any cleanup code go here
    49.     '' ensure that you close all open resources before exitting out of this Method.
    50.     '' try to skip off whatever is not desperately necessary if CancellationPending is True
    51.  
    52.     '' set the e.Cancel to True to indicate to the RunWorkerCompleted that you cancelled out
    53.     If BackgroundWorker1.CancellationPending Then
    54.         e.Cancel = True
    55.         BackgroundWorker1.ReportProgress(100, "Cancelled.")
    56.     End If
    57. End Sub
    58.  
    59. Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    60.     '' This event is fired when you call the ReportProgress method from inside your DoWork.
    61.     '' Any visual indicators about the progress should go here.
    62.     Label1.Text = CType(e.UserState, String)
    63.     Label2.Text = e.ProgressPercentage.ToString & "% complete."
    64. End Sub
    65.  
    66. Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    67.     '' This event is fired when your BackgroundWorker exits.
    68.     '' It may have exitted Normally after completing its task,
    69.     '' or because of Cancellation, or due to any Error.
    70.  
    71.     If e.Error IsNot Nothing Then
    72.         '' if BackgroundWorker terminated due to error
    73.         MessageBox.Show(e.Error.Message)
    74.         Label1.Text = "Error occurred!"
    75.  
    76.     ElseIf e.Cancelled Then
    77.         '' otherwise if it was cancelled
    78.         MessageBox.Show("Task cancelled!")
    79.         Label1.Text = "Task Cancelled!"
    80.  
    81.     Else
    82.         '' otherwise it completed normally
    83.         MessageBox.Show("Task completed!")
    84.         Label1.Text = "Error completed!"
    85.     End If
    86.  
    87.     Button1.Enabled = True
    88.     Button2.Enabled = False
    89. End Sub

    Run the code and see that the Start and Cancel works smoothly.
    Pay attention to the comments, to adapt this stub as per your actual needs.


    [EDIT: updated with more information]
    (copied here from: http://www.vbforums.com/showpost.php...32&postcount=8)


    Passing more information than just a String value via ProgressChanged event
    Actually you should never try to access any Control inside the DoWork.

    There are just two ways you would need them inside the DoWork event.
    1. You want to pick up some value from some control.
    2. You want to update some control's value.


    To pick some value from any control, put such values in variables, so that you don't need to reference the controls from inside the DoWork event. Do that before you call the RunWorkerAsync method (which in turn fires the DoWork event).

    If you want to set something in any control, you should use the ReportProgress method to pass your values out of BackgroundWorker. The values you pass from ReportProgress can be accessed from the ProgressChanged event. You can assign those values to your controls or do anything else you want to do with them.
    So you do:
    Code:
    ' Inside DoWork event
    worker.ReportProgress(10, "Run coding 1")
    
    ' In ProgressChanged event
    Me.Label1.Text = CType(e.UserState, String)
    This was just a simple example where a string is passed.

    But in many cases you may want to pass more information than this to the ProgressChanged event.
    e.g. you have 10 labels, and you also want to pass which label's text property to update, along with the string value you want to set.

    Fortunately, the ReportProgress can pass a value of type Object to the ProgressChanged event. This means that you can pass virtually anything via that method. It can be as small as a string or number, or it can be a complex structure like some class object or array etc.

    Below is an example where I pass the control name and its value to set.

    1. Create a structure/class which can hold the control name (name of label) and the text value to set.
    Code:
    Public Structure ControlWithText
        Public ControlName As Control
        Public Text As String
    
        Public Sub New(ByVal ctrl As Control, ByVal text As String)
            Me.ControlName = ctrl
            Me.Text = text
        End Sub
    End Structure
    2. From inside the DoWork event, you pass an object instance of this structure.
    e.g.
    Code:
    worker.ReportProgress(10, New ControlWithText(Label1, "Run coding 1"))
    
    worker.ReportProgress(20, New ControlWithText(Label2, "Run coding 2"))
    3. Now in your ProgressChanged event, you will have this object available. Just get the control name and the text out of it and do your task appropriately.
    Code:
    If TypeOf e.UserState Is ControlWithText Then
        Dim cwt As ControlWithText = CType(e.UserState, ControlWithText)
        cwt.ControlName.Text = cwt.Text
    End If
    Last edited by Pradeep1210; May 31st, 2012 at 02:09 AM. Reason: added support for things more than just String
    Pradeep, Microsoft MVP (Visual Basic)
    Please appreciate posts that have helped you by clicking icon on the left of the post.
    "A problem well stated is a problem half solved." — Charles F. Kettering

    Read articles on My Blog101 LINQ SamplesJSON ValidatorXML Schema Validator"How Do I" videos on MSDNVB.NET and C# ComparisonGood Coding PracticesVBForums Reputation SaverString EnumSuper Simple Tetris Game


    (2010-2013)
    NB: I do not answer coding questions via PM. If you want my help, then make a post and PM me it's link. If I can help, trust me I will...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width