Vb.Net BackgroundWorker To Invoke ListBox


This article is written by Pon Saravanan  on 09-Feb-11 Last modified on :09-Feb-11





VB.Net Tutorial - BackgroundWorker and Invoke

Those who have worked extensively on threading will feel that this article is simple. But for who are quite new to threading and learning the Asynchronous operations, this article can be useful to figure out how to introduce the Asynchronous to the existing methods to enhance the performance.

Why there is a need of Asynchronous or Background

Without the BackgroundWorker worker, you can still build a good application. However with the help of asynchronous operations, you can improve the processing time and hence the application will be highly responsive.

Run the source code sequential

I can prove that with the example I have given in this article. If you look at the source code event btnStart_Click, I have commented out the function BgWorkerFunction. To run without asynchronous you may comment out the BackgroundWorker1.RunWorkerAsync() function call and uncomment the BgWorkerFunction call. Now you can notice that the first ListBox is loaded fully before the second ListBox started loading. It shows that the operations are sequential.

Screen Capture

Run with the BackgroundWorker

 Now uncomment the BackgroundWorker1.RunWorkerAsync() and comment out the BgWorkerFunction call in the event btnStart_Click. You can see that both the ListBoxes will be loaded concurrently. So user can see the progress on two different but related operations in parallel.

Screen Capture

Start BackgroundWorker

BackgroundWorker is a UI control in the toolbox. So you can drag that from toolbox to the windows form. Before start using it you may need to specify few properties. WorkerReportsProgress to true if you need to show the progress to user. You may use the event ProgressChanged Event.  If everything is configured, calling the RunWorkerAsync will initiate the process.

BackgroundWorker.DoWork

The actual operations that have to be run in background have to be written here. Keep in mind this is going to run in another thread NOT in the main thread. So we need to make the necessary invoke calls if the cross thread communications are necessary. You may use the Invoke method, and InvokeRequired property from all the (if not most) controls. Note: Intellisense won’t show these out of the box, you may need to type few letters then Intellisense will list that out.

Access the Listbox from BackgroundWorker using Invoke

As I have explained earlier, it is necessary to use invoke when there is a need for cross thread communications. In our case the ListBox is in the main thread and BackgroundWorker  runs the operations in another thread. When you are running the function BgWorkerFunction from btnStart_Click event, there is no need for invoke required. But when the same function is being called from the event BackgroundWorker.DoWork, there is a need of Invoke. This can be detected in the runtime using the property InvokeRequred. This property is available in every control in the toolbox (refer the previous section on this for details).

Delegates for Invoke

The invoke function needs a delegate for accessing the control in the main thread. So I have created a delegate named as AddItemsToListBoxDelegate with same signature as my target method AddItemsToListBox. Now the AddItemsToListBox expects two parameters ToListBox, and AddText, so you need to pass these two values when using the delegate for invoking the method AddItemsToListBox. This can be achieved by the overloaded Invoke which accepts parameters to the target method as an object array. With this you can use the BackgroundWorker to invoke the controls in the main thread.

Source Code

Form((.Vb)

Imports System.ComponentModel
Public Class Form1
    Public Delegate Sub AddItemsToListBoxDelegate( _
                            ByVal ToListBox As ListBox, _
                            ByVal AddText As String)
    Private Sub btnStart_Click(ByVal sender As System.Object, _
                               ByVal e As System.EventArgs) Handles btnStart.Click
        BackgroundWorker1.RunWorkerAsync()
        MainFunction()
        'BgWorkerFunction()
    End Sub
    Private Sub MainFunction()
        Dim StartDate = Now
        Dim Counter = 0
        Do Until Counter > 20
            AddItemsToListBox(lstMainFunction, "Current Index is " & Counter)
            Counter += 1
            Threading.Thread.Sleep(100)
            Application.DoEvents() 'if you dont instruct App to doevents, 
            'you will not see any background work, the work looks sequential.
        Loop
    End Sub
    Private Sub BgWorkerFunction()
        Dim StartDate = Now
        Dim Counter = 0
        Do Until Counter > 20
            'if you call this from a thread which is not the main/form then
            'invoke is required.
            If (lstBgWorker.InvokeRequired) Then
                lstBgWorker.Invoke( _
                        New AddItemsToListBoxDelegate(AddressOf AddItemsToListBox), _
                        New Object() {lstBgWorker, "Current Index is " & Counter})
            Else
                lstBgWorker.Items.Add("Current Index is " & Counter)
                lstBgWorker.SelectedIndex = lstBgWorker.Items.Count - 1
            End If
            Counter += 1
            Threading.Thread.Sleep(100)
            Application.DoEvents()
        Loop
    End Sub
    Private Sub AddItemsToListBox(ByVal ToListBox As ListBox, _
                                  ByVal AddText As String)
        ToListBox.Items.Add(AddText)
        ToListBox.SelectedIndex = ToListBox.Items.Count - 1
    End Sub
    Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, _
                                         ByVal e As DoWorkEventArgs) _
                                         Handles BackgroundWorker1.DoWork
        BgWorkerFunction()
    End Sub
End Class

Designer(Designer.vb)

Imports System.Drawing
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form1
    Inherits System.Windows.Forms.Form
    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub
    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer
    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer. 
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
        Me.BackgroundWorker1 = New System.ComponentModel.BackgroundWorker
        Me.lstMainFunction = New System.Windows.Forms.ListBox
        Me.lstBgWorker = New System.Windows.Forms.ListBox
        Me.lblMainFunction = New System.Windows.Forms.Label
        Me.lblBgWorker = New System.Windows.Forms.Label
        Me.btnStart = New System.Windows.Forms.Button
        Me.SuspendLayout()
        '
        'BackgroundWorker1
        '
        Me.BackgroundWorker1.WorkerReportsProgress = True
        '
        'lstMainFunction
        '
        Me.lstMainFunction.Font = New Font("Microsoft Sans Serif", 9.75!, _
                                                          FontStyle.Bold, _
                                                          GraphicsUnit.Point, _
                                                          CType(0, Byte))
        Me.lstMainFunction.FormattingEnabled = True
        Me.lstMainFunction.ItemHeight = 16
        Me.lstMainFunction.Location = New Point(2, 56)
        Me.lstMainFunction.Name = "lstMainFunction"
        Me.lstMainFunction.Size = New Size(137, 340)
        Me.lstMainFunction.TabIndex = 0
        '
        'lstBgWorker
        '
        Me.lstBgWorker.Font = New Font("Microsoft Sans Serif", 9.75!, _
                                                      FontStyle.Bold, _
                                                      GraphicsUnit.Point, _
                                                      CType(0, Byte))
        Me.lstBgWorker.FormattingEnabled = True
        Me.lstBgWorker.ItemHeight = 16
        Me.lstBgWorker.Location = New Point(158, 56)
        Me.lstBgWorker.Name = "lstBgWorker"
        Me.lstBgWorker.Size = New Size(137, 340)
        Me.lstBgWorker.TabIndex = 1
        '
        'lblMainFunction
        '
        Me.lblMainFunction.AutoSize = True
        Me.lblMainFunction.Font = New Font("Microsoft Sans Serif", 9.75!, _
                                                          FontStyle.Bold, _
                                                          GraphicsUnit.Point, _
                                                          CType(0, Byte))
        Me.lblMainFunction.Location = New Point(-1, 40)
        Me.lblMainFunction.Name = "lblMainFunction"
        Me.lblMainFunction.Size = New Size(66, 16)
        Me.lblMainFunction.TabIndex = 2
        Me.lblMainFunction.Text = "Function"
        '
        'lblBgWorker
        '
        Me.lblBgWorker.AutoSize = True
        Me.lblBgWorker.Font = New Font("Microsoft Sans Serif", 9.75!, _
                                                      FontStyle.Bold, _
                                                      GraphicsUnit.Point, _
                                                      CType(0, Byte))
        Me.lblBgWorker.Location = New Point(160, 39)
        Me.lblBgWorker.Name = "lblBgWorker"
        Me.lblBgWorker.Size = New Size(145, 16)
        Me.lblBgWorker.TabIndex = 3
        Me.lblBgWorker.Text = "Background Worker"
        '
        'btnStart
        '
        Me.btnStart.Font = New Font("Microsoft Sans Serif", 9.75!, _
                                                   FontStyle.Bold, _
                                                   GraphicsUnit.Point, _
                                                   CType(0, Byte))
        Me.btnStart.Location = New Point(2, 12)
        Me.btnStart.Name = "btnStart"
        Me.btnStart.Size = New Size(75, 23)
        Me.btnStart.TabIndex = 4
        Me.btnStart.Text = "Start"
        Me.btnStart.UseVisualStyleBackColor = True
        '
        'Form1
        '
        Me.AutoScaleDimensions = New SizeF(6.0!, 13.0!)
        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        Me.ClientSize = New Size(305, 397)
        Me.Controls.Add(Me.btnStart)
        Me.Controls.Add(Me.lblBgWorker)
        Me.Controls.Add(Me.lblMainFunction)
        Me.Controls.Add(Me.lstBgWorker)
        Me.Controls.Add(Me.lstMainFunction)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)
        Me.PerformLayout()
    End Sub
    Friend WithEvents BackgroundWorker1 As System.ComponentModel.BackgroundWorker
    Friend WithEvents lstMainFunction As System.Windows.Forms.ListBox
    Friend WithEvents lstBgWorker As System.Windows.Forms.ListBox
    Friend WithEvents lblMainFunction As System.Windows.Forms.Label
    Friend WithEvents lblBgWorker As System.Windows.Forms.Label
    Friend WithEvents btnStart As System.Windows.Forms.Button
End Class



« Previous -







Comments
  • GUEST
    You can add text items to a listbox from a Backgroundworker's ProgressChange event handler.

    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged

    'Post Program Messages to Listbox
    lbStatus.Items.Add(e.UserState)

    End Sub

    The e.UserState is just a string variable that can be set and then have the event ProgressChanged called from anywhere in the background thread code with something like:

    BackgroundWorker1.ReportProgress(0, "Hello World")

    It's simple and works well.

    Though using delegates and invoke might be able to accomplish something else.

    Regards

    Mikall
    6/11/2011 8:37:19 PM

  • GUEST
    abcdes 12/29/2011 9:57:30 PM


Comments
   
Captcha Image
For you specially:  
Captcha Text Enter the text in the image.(Not Case sensitive)    



Spam Bot Trap



   



Select Theme
White
Gray
Blue
Brown
GraySimple