# VBForums CodeBank > CodeBank - Visual Basic .NET >  Using the BackgroundWorker Component

## jmcilhinney

C# version here.

Create a new Windows Forms project.  Add a Label, a ProgressBar and a BackgroundWorker to the form.  Set the BackgroundWorker's WorkerReportsProgress property to True.  Add the following code then run the project.
VB.NET Code:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load    'Raise the DoWork event in a worker thread.    Me.BackgroundWorker1.RunWorkerAsync()End Sub 'This method is executed in a worker thread.Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, _                                     ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork    Dim worker As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)     For i As Integer = 1 To 100        'Raise the ProgressChanged event in the UI thread.        worker.ReportProgress(i, i & " iterations complete")         'Perform some time-consuming operation here.        Threading.Thread.Sleep(250)    Next iEnd Sub 'This method is executed in the UI thread.Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, _                                              ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged    Me.ProgressBar1.Value = e.ProgressPercentage    Me.Label1.Text = TryCast(e.UserState, String)End Sub 'This method is executed in the UI thread.Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, _                                                 ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted    Me.Label1.Text = "Operation complete"End Sub

----------


## jmcilhinney

E.g. Perform a loop in the worker thread with a number of iterations determined by the value set in a NumericUpDown:
VB.NET Code:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Me.BackgroundWorker1.RunWorkerAsync(CInt(Me.NumericUpDown1.Value))
End Sub
 Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, _
                                     ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    Dim worker As BackgroundWorker = DirectCast(sender, BackgroundWorker)
    Dim iterationCount As Integer = 0
     If TypeOf e.Argument Is Integer Then
        iterationCount = CInt(e.Argument)
    End If
     For i As Integer = 1 To iterationCount Step 1
        'Do something here.
    Next i
End Sub

----------


## shakti5385

How to fill multiple combo using the background worker component!

I done this for a single combo but for the multiple combo it is not working!
Please guide me


VB.NET Code:
Private Sub BackgroundWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker.DoWork
        Dim worker As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
        rawMaterialCategoryDataTable = rawMaterialCategory.ReturnDataTable(, "ORDER BY CategoryName") 'Returnning a Datatable
        Dim dataColumn As New DataColumn
        dataColumn.DataType = GetType(Integer)
        dataColumn.ColumnName = "SearchingCode"
        Dim searchingCode As Integer
        rawMaterialCategoryDataTable.Columns.Add(dataColumn)
        For Each dataRow As DataRow In rawMaterialCategoryDataTable.Rows
            worker.ReportProgress(0, dataRow("CategoryName"))
            rawMaterialCategoryDataTable.Rows(searchingCode).Item("SearchingCode") = searchingCode + 1
            searchingCode += 1
        Next dataRow
    End Sub
     Private Sub BackgroundWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker.ProgressChanged
        If Not e.UserState Is Nothing Then
            Me.sRawMaterialCategory.Items.Add(CStr(e.UserState).Trim) 'Adding In the combo Box
        Else
            'Me.ProgressBar1.Value = e.ProgressPercentage
        End If
    End Sub

----------


## jmcilhinney

Here are two examples that contrast using a BackgroundWorker to update the UI as the work is done and using it to update the UI only once the work is complete:
vb.net Code:
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, _                                     ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork    Dim worker As BackgroundWorker = DirectCast(sender, BackgroundWorker)     For Each filePath As String In IO.Directory.GetFiles(My.Computer.FileSystem.SpecialDirectories.MyDocuments)        worker.ReportProgress(0, IO.Path.GetFileName(filePath))    Next filePathEnd Sub Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, _                                              ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged    Dim fileName As String = DirectCast(e.UserState, String)     Me.ListBox1.Items.Add(fileName)End Sub

vb.net Code:
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, _                                     ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork    Dim worker As BackgroundWorker = DirectCast(sender, BackgroundWorker)    Dim fileNames As String() = IO.Directory.GetFiles(My.Computer.FileSystem.SpecialDirectories.MyDocuments)     For index As Integer = 0 To fileNames.GetUpperBound(0) Step 1        fileNames(index) = IO.Path.GetFileName(fileNames(index))    Next index     e.Result = fileNamesEnd Sub Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, _                                                 ByVal e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted    Dim fileNames As String() = DirectCast(e.Result, String())     Me.ListBox1.Items.AddRange(fileNames)End Sub
These examples show how you can pass data to the UI from a BackgroundWorker in two different ways without having to explicitly delegate, which is one of the first things everyone has trouble with when multi-threading.

Note that for the first example to work the WorkerReportsProgress property must be set to True.

----------


## scootabug

I am trying to follow your first post and I get this error:

"This BackgroundWorker states that it doesn't report progress. Modify WorkerReportsProgress to state that it does report progress."

Everything works okay when I comment out the line that errors...

Do you have the quick solution to this problem?

Nicely done all the same.  Cheers.

----------


## jmcilhinney

> I am trying to follow your first post and I get this error:
> 
> "This BackgroundWorker states that it doesn't report progress. Modify WorkerReportsProgress to state that it does report progress."
> 
> Everything works okay when I comment out the line that errors...
> 
> Do you have the quick solution to this problem?
> 
> Nicely done all the same.  Cheers.


The error message says this:


> Modify WorkerReportsProgress to state that it does report progress.


In post #1 I said this:


> Set the BackgroundWorker's WorkerReportsProgress property to True.


In post #4 I said this:


> Note that for the first example to work the WorkerReportsProgress property must be set to True.


Are you noticing a theme here?

----------


## scootabug

Sorry, my bad.  I noticed the property after I'd posted, hadn't got a chance to come back here until now to say 'nevermind!'.  Thanks though, you are invaluable.

----------


## zxed

thanks for the outline., it helped me understand the concept of using dowork with triggering RunWorkerCompleted and progresschanged..

question... this was posted in 2007.. im guessing it has not really for .net 3.5... is it?

now., is it possible to tie in the background worker with the calls to a webservice? im sure there is.. i know i have seen the async calls somewhere., possibly with the buffer = false?.. i ask because... i have a handheld device, that queries a webservice for a dataset, the webservice generates the dataset, and it has around 20,000 records... surprisingly., it generates the data in about a minute,. and then the device inserts the data into its sqlce db.. so, im wondering if there is a way to turn off buffering on the webserice call and populate the database as data comes back... rather than., send command-> wait for entire dataset -> insert data set...... i want to do a send command -> wait a bit, ->do a bit -> loop a bit  :Wink: 

sadly i have to communicate thru a web service... client needs top security and will not allow access to db's directly from desktop/work station... all db's must be accessed thru web serivce...

----------


## jmcilhinney

> thanks for the outline., it helped me understand the concept of using dowork with triggering RunWorkerCompleted and progresschanged..
> 
> question... this was posted in 2007.. im guessing it has not really for .net 3.5... is it?
> 
> now., is it possible to tie in the background worker with the calls to a webservice? im sure there is.. i know i have seen the async calls somewhere., possibly with the buffer = false?.. i ask because... i have a handheld device, that queries a webservice for a dataset, the webservice generates the dataset, and it has around 20,000 records... surprisingly., it generates the data in about a minute,. and then the device inserts the data into its sqlce db.. so, im wondering if there is a way to turn off buffering on the webserice call and populate the database as data comes back... rather than., send command-> wait for entire dataset -> insert data set...... i want to do a send command -> wait a bit, ->do a bit -> loop a bit 
> 
> sadly i have to communicate thru a web service... client needs top security and will not allow access to db's directly from desktop/work station... all db's must be accessed thru web serivce...


The BackgroundWorker class hasn't changed at all (as far as I'm aware) from .NET 2.0 to 3.5.

My knowledge of Web Services is not extensive but, as far as I'm aware, calling a web method is essentially the same as calling a local method.  If your method returns a DataSet then you can't really do anything until that method returns because you have no data until then.  If you can somehow access the data piecemeal then you can certainly use it as you receive it.  That's beyond the scope of this thread though.  I'd suggest you post a question relating to this specifically on the appropriate forum.

----------


## JuggaloBrotha

> question... this was posted in 2007.. im guessing it has not really for .net 3.5... is it?


The 3.5 framework literally sits on top of the 3.0 framework and the 3.0 framework literally sits on top of the 2.0 framework which means unless there's a new backgroundworker in the 3.5 framework (which you would know about it if you were using it because you would have to explicitly reference it) the only background worker is the 2.0 one.

Another interesting tip: the 3.0 and 3.5 frameworks don't have a CLR, it's the 2.0 framework that has the CLR we all use and love.

----------


## zxed

thanks for getting back to me., i will figure out the web service thingy, and create a sep thread with code + examples.  :Smilie:

----------


## Xancholy

I have a question. When a large number of files are being copied, how can I accurately show overall process progressbar feedback ? Update the form's progressbar from the backgroundworker...

Thanks for any help.

----------


## jmcilhinney

> I have a question. When a large number of files are being copied, how can I accurately show overall process progressbar feedback ? Update the form's progressbar from the backgroundworker...
> 
> Thanks for any help.


This thread already shows you how to update a ProgressBar to indicate the progress of a background operation so I'm not going to go over that.  Your issue is determining what constitutes 100% and determining what your current percentage is.

Now, the first thing to note is that progress does NOT have to represent a percentage.  You can, if you want, set the Maximum of your ProgressBar to 100 and then set the Value to a percentage.  Alternatively you could set the Maximum to the number files you need to process and then increment the Value by 1 each time a file is processed.  Another alternative would be to set the Maximum to the total size of all the files to be processed and then increment the Value by the size of the file each time one is processed.

----------


## Xancholy

OK thanks.

----------


## jmcilhinney

> The other option would be to measure total of filesizes being copied and progressbar it in a linear way, yes ?


The only time you can update the ProgressBar is after each file has been processed because copying a file is a synchronous operation.  You can't provide any feedback during the copy operation.

----------


## doran_doran

See the other post.

----------


## jmcilhinney

doran, you're going to have to tidy that post up before I'll even consider looking at it.

----------


## sauronsmatrix

I found that I didn't even need the Sleep from the Threading. The worker seems to use just the right amount of resources to get the task done without crashing or overloading.

----------


## jmcilhinney

Here is a new example based on the code from the first post.  Follow the same instructions as before but this time also set the WorkerSupportsCancellation property of the BackgroundWorker to True and add a Button to the form.  Now add this code to your form:
vb.net Code:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load    'Raise the DoWork event in a worker thread.    Me.BackgroundWorker1.RunWorkerAsync()End Sub 'This method is executed in a worker thread.Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, _                                     ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork    Dim worker As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)     For i As Integer = 1 To 100        If worker.CancellationPending Then            'The user has cancelled the background operation.            e.Cancel = True            Exit For        End If         'Raise the ProgressChanged event in the UI thread.        worker.ReportProgress(i, i & " iterations complete")         'Perform some time-consuming operation here.        Threading.Thread.Sleep(250)    Next iEnd Sub 'This method is executed in the UI thread.Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, _                                              ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged    Me.ProgressBar1.Value = e.ProgressPercentage    Me.Label1.Text = TryCast(e.UserState, String)End Sub 'This method is executed in the UI thread.Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, _                                                 ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted    If e.Cancelled Then        'The background operation was cancelled.        Me.Label1.Text = "Operation cancelled"    Else        'The background operation completed normally.        Me.Label1.Text = "Operation complete"    End IfEnd Sub Private Sub Button1_Click(ByVal sender As Object, _                          ByVal e As EventArgs) Handles Button1.Click    'Only cancel the background opertion if there is a background operation in progress.    If Me.BackgroundWorker1.IsBusy Then        Me.BackgroundWorker1.CancelAsync()    End IfEnd Sub
If you run the project and let it go then the ProgressBar will fill and eventually the Label will report that the operation completed.  If, however, you click the Button at some point, the Progressbar will halt and the Label will report that the operation was cancelled.

----------


## Xancholy

nice

----------


## numbskull77

> Create a new Windows Forms project.  Add a Label, a ProgressBar and a BackgroundWorker to the form.  Set the BackgroundWorker's WorkerReportsProgress property to True.  Add the following code then run the project.
> VB.NET Code:
> Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
>     'Raise the DoWork event in a worker thread.
>     Me.BackgroundWorker1.RunWorkerAsync()
> End Sub
>  'This method is executed in a worker thread.
> Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, _
>                                      ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
> ...


hi, i used the above code .. and i got this error:

Cross-thread operation not valid: Control 'Label1' accessed from a thread other than the thread it was created on.

need your advise...

----------


## jmcilhinney

> hi, i used the above code .. and i got this error:
> 
> Cross-thread operation not valid: Control 'Label1' accessed from a thread other than the thread it was created on.
> 
> need your advise...


You certainly didn't use just that code.  If you go back to post #4 I specifically demonstrate how to access controls using a BackgroundWorker, i.e. either from the ProgressChanged event handler or the RunWorkerCompleted event handler.  That's because they are both executed in the UI thread.  You cannot access controls from the DoWork event handler, as you must be, because it is executed in a background thread.

If you can't use those two aforementioned events for some reason then you will need to use explicit delegation.  Follow the Controls & Multi-threading link in my signature for an explanation of why and how.

----------


## killer7k

Hi John , 

i have a problem with stopping the BackgroundWorker
i have 2 button start & stop 
so basically the start button download some data using webclient



```
bgwkdata.RunWorkerAsync()
```

and for stop button i have 



```
bgwkdata.CancelAsync()
```

so the problem is the stop button not doing the job the BackgroundWorker is still running 
btw i have set option true to Workersupportcancellation and also



```
If bgwkdata.CancellationPending Then

            e.Cancel = True

            Exit Sub

        End If
```

Thanks  :Smilie:

----------


## jmcilhinney

> Hi John , 
> 
> i have a problem with stopping the BackgroundWorker
> i have 2 button start & stop 
> so basically the start button download some data using webclient
> 
> 
> 
> ```
> ...


Presumably that code is never being hit during your time-consuming operation.  For instance, there's not much point doing this:
vb.net Code:
If myBGW.CancellationPending Then
    e.Cancel = True
    Exit Sub
End If
 For count As Integer = 1 To 100
    'Do something.
Next
 If myBGW.CancellationPending Then
    e.Cancel = True
    Exit Sub
End If
because you don't ever check whether the operation needs to be cancelled anywhere in the loop.  You'd need to check inside the loop.  If you don't have a loop then you'll just have to check in between the steps of your operation.  You can only check whether the operation needs to be cancelled while the background thread is not busy doing something else.  If your background thread simply makes one synchronous method call then you're out of luck.  It simply can't be cancelled.  There need to be breaks somewhere in your code that you can insert those checks.

----------


## killer7k

Hi John , 

here you what i have done 



```
   Private Sub bgwkdata_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwkdata.DoWork
      
  If bgwkdata.CancellationPending Then

            e.Cancel = True

            Exit Sub

        End If

//my boucle here

 If bgwkdata.CancellationPending Then

            e.Cancel = True

            Exit Sub

        End If
```

and on btnstop :



```
Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click


        bgwkdata.CancelAsync()






    End Sub
```

Edit : i get it to work i placed the code in the boucle 

Thanks

----------


## kuldevbhasin

hi jmc
can we use background worker on smart device application ?
i am developing a app. in vb.net 2008 for a smart device.
i am trying to locate the background worker that u mentioned to be added to the form but am not able to find it.
do i have to import something to get that option or what ?
pls. guide
thankx a lot

----------


## JuggaloBrotha

> hi jmc
> can we use background worker on smart device application ?
> i am developing a app. in vb.net 2008 for a smart device.
> i am trying to locate the background worker that u mentioned to be added to the form but am not able to find it.
> do i have to import something to get that option or what ?
> pls. guide
> thankx a lot


The location of the BW is this: System.ComponentModel.BackgroundWorker

So I would start by looking for it in the System.ComponentModel namespace

----------


## jmcilhinney

> hi jmc
> can we use background worker on smart device application ?
> i am developing a app. in vb.net 2008 for a smart device.
> i am trying to locate the background worker that u mentioned to be added to the form but am not able to find it.
> do i have to import something to get that option or what ?
> pls. guide
> thankx a lot


The CF contains less than the full Framework and the BackgroundWorker class is simply not necessary.  It's convenient but it doesn't do anything you can't do yourself with the Thread class and delegates.

----------


## kuldevbhasin

thankx for ur reply
i have developed a prog. for bills generation on a smart device. the smart device is using GPRS and web service to connect to the data stored on the server.
what i was thinking was that if GPRS is not available then the prog. should generate and store the data on the device itself as sqlce is available on the device. now as soon as the GPRS is available i was thinking of sending the data to the web server in the background.
for this reason was trying for background worker. so that while the bills get generated the local bills r also getting posted simultaniously in the background. 
am i right in this thinking or is there any other way.
pls. guide.
thankx

----------


## jmcilhinney

> thankx for ur reply
> i have developed a prog. for bills generation on a smart device. the smart device is using GPRS and web service to connect to the data stored on the server.
> what i was thinking was that if GPRS is not available then the prog. should generate and store the data on the device itself as sqlce is available on the device. now as soon as the GPRS is available i was thinking of sending the data to the web server in the background.
> for this reason was trying for background worker. so that while the bills get generated the local bills r also getting posted simultaniously in the background. 
> am i right in this thinking or is there any other way.
> pls. guide.
> thankx


That is not the topic of this thread.  You should ask such questions in new threads in the appropriate forum.

----------


## snakeman

hey jim 
why do you declare a new worker:-

vb Code:
Dim worker As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
you already have one 
i couldn't understand it  :Confused: 
and why you didn't dispose the backgroundworker?

----------


## jmcilhinney

> hey jim 
> why do you declare a new worker:-
> 
> vb Code:
> Dim worker As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
> you already have one 
> i couldn't understand it 
> and why you didn't dispose the backgroundworker?


There's a difference between "declaring" and "creating".  That code declares a BackgroundWorker variable but it does NOT create a BackgroundWorker object.  It simply takes the 'sender' parameter, which is the object that raised the event, and casts it as type BackgroundWorker.  By assigning that to the local variable I am then able to access members of the BackgroundWorker type, which I couldn't do on 'sender' because it is type Object.

Yes, I could have simply used the existing member variable, i.e. Me.BackgroundWorker1, and had the same result.  The reason that casting the 'sender' is useful is that it allows you to handle events for multiple BackgroundWorkers with the same method.  If you only have one BackgroundWorker then it's not required, although it is considered best practice.

----------


## snakeman

thx jim

----------


## Tommi

Cant seem to figure out what Im doing wrong here, I get a type expected error from vb when I try to compile from the first backgroundWorker part of this (it automatically makes it a lowercase "b" could that have something to do with this?)


```
 Dim worker As backgroundWorker = DirectCast(sender, backgroundWorker)
```

entire code


```
Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Raise the DoWork event in a worker thread.
        Me.BackgroundWorker1.RunWorkerAsync()
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.BackgroundWorker1.RunWorkerAsync(CInt(Me.NumericUpDown1.Value))
    End Sub
    'This method is executed in a worker thread.
    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, _
                                     ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim worker As backgroundWorker = DirectCast(sender, backgroundWorker)
        Dim iterationCount As Integer = 0

        If TypeOf e.Argument Is Integer Then
            iterationCount = CInt(e.Argument)
        End If

        For i As Integer = 1 To iterationCount Step 1
            'Do something here.
        Next i
    End Sub

    'This method is executed in the UI thread.
    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, _
                                                        ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        Me.ProgressBar1.Value = e.ProgressPercentage
        Me.Label1.Text = TryCast(e.UserState, String)

    End Sub

    'This method is executed in the UI thread.
    Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, _
                                                           ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        Me.Label1.Text = "Operation complete"
    End Sub
End Class
```

Thanks in advance for any help!

----------


## jmcilhinney

> Cant seem to figure out what Im doing wrong here, I get a type expected error from vb when I try to compile from the first backgroundWorker part of this (it automatically makes it a lowercase "b" could that have something to do with this?)
> 
> 
> ```
>  Dim worker As backgroundWorker = DirectCast(sender, backgroundWorker)
> ```
> 
> entire code
> 
> ...


The BackgroundWorker class is a member of the System.ComponentModel namespace.  If you haven't imported that namespace then you'll need to qualify the class name with the namespace, as for all the 'e' parameters in the event handlers.

----------


## Tommi

> The BackgroundWorker class is a member of the System.ComponentModel namespace.  If you haven't imported that namespace then you'll need to qualify the class name with the namespace, as for all the 'e' parameters in the event handlers.


It's working now, thanks for the help!

----------


## Lasering

Excellent post! It has helped me a lot!! Keep up the always great work jmcilhinney!

----------


## cengineer

I have tried to adapt your code to a console application and it seems to working as far as running the background worker, and I do have the ProgressChanged and RunWorkerCompleted functions to monitor it, the process ends after one cycle of its do work process.


```
  
While Not response.Equals("3")
                Try

                    Console.Write("Enter choice: ")
                    response = Console.ReadLine()
                    Console.WriteLine()
                    If response.Equals("1") Then
                        Console.WriteLine("Thread 1 doing work" & vbNewLine)
                        engine.LoadFile()
                        'tm.SetApartmentState(ApartmentState.STA)
                        'tm.Start()

                        response = String.Empty
                    ElseIf response.Equals("2") Then
                        Console.WriteLine("Starting a second Thread")
                        'ts.Start()
                        report()
                        response = String.Empty
                    End If

                    'ts.Join()
                    'tm.Join()

                Catch ex As Exception
```

as you can see the commented parts was an attempt to try threads; wasnt successful.

Here is where the background worker is being called from, sub engine.loadfile()



```
bgw.WorkerReportsProgress = True

       AddHandler bgw.DoWork, New DoWorkEventHandler(AddressOf Search)
       bgw.RunWorkerAsync()
      AddHandler bgw.ProgressChanged, New ProgressChangedEventHandler(AddressOf ProgressChanged)
      AddHandler bgw.RunWorkerCompleted, New RunWorkerCompletedEventHandler(AddressOf RunWorkerComplete)
```

the actual do work process



```
Private Sub Search(ByVal sender As Object, ByVal e As DoWorkEventArgs)
...
              BloObj.Main(connectionString, userAgent, fileName, clientName, clientProj)
                Dim i As Integer
                For i = 1 To 100
                    CType(sender, BackgroundWorker).ReportProgress(i)
                    Thread.Sleep(100)
                Next
                Console.ResetColor()
                Console.Write("Search Complete, Do you wish to generate queries, y or n? ")
reply = Console.ReadLine()
                If reply = "y" Then
                    report()
                ElseIf reply = "n" Then
                    Console.Clear()
                    main()
                End If
            Catch ex As Exception
                errormessage = ex.Message

            End Try
```

Any ideas appreciated.

----------


## jmcilhinney

> I have tried to adapt your code to a console application and it seems to working as far as running the background worker, and I do have the ProgressChanged and RunWorkerCompleted functions to monitor it, the process ends after one cycle of its do work process.
> 
> 
> ```
>   
> While Not response.Equals("3")
>                 Try
> 
>                     Console.Write("Enter choice: ")
> ...


Your code doesn't really make sense to me.  I don't see why you have a BGW at all.  You seem to be prompting the user for data from the background thread.  Usually the point of background threads is to perform time-consuming processing in the background so that the user can still interact with the application in the foreground.  What's the point of having multiple threads in your case?

----------


## cengineer

Sorry about the confusion... I need to implement threads on the menu options I have and the one process is a long search crawling process which after it starts does not involve any user interaction.
I figured the background process would work well here.



```
Console.ResetColor()
            Console.Write("Begin Search -- Discovery Search, y or n? ")
            response1 = Console.ReadLine()
            If response1 = "y" Then
                Console.ForegroundColor = ConsoleColor.White
                Console.WriteLine()

                Console.Write("Enter client name: ")
                clientName = Console.ReadLine()
                Console.WriteLine()
                Console.Write("Enter client project: ")
                clientProj = Console.ReadLine()
                ' This is where I would like to call the background process
                bgw.WorkerReportsProgress = True

                AddHandler bgw.DoWork, New DoWorkEventHandler(AddressOf Search)
                bgw.RunWorkerAsync()
                AddHandler bgw.ProgressChanged, New ProgressChangedEventHandler(AddressOf ProgressChanged)
                AddHandler bgw.RunWorkerCompleted, New RunWorkerCompletedEventHandler(AddressOf RunWorkerComplete)
                'bgw.ReportProgress(80)
                ' I was unable to make sure the process returned to the menu options so I put in a return here to the main where its called from
                Return
                'Search()
```

The actual search process only contains a user response after it supposed to complete. The background process is not only one function but involves calling other classes and functions to the crawling process. As i mentioned before I tried using threads but found that it did not run in the background as I intended. Also the background process is stopping before completion without any indication. I placed breakpoints to catch the possible errors but the app just ends after a while.

----------


## techgnome

well, for starters, your addhandlers for the progress change and completed events should be set BEFORE invoking the thread.
Also... what does the search function do? And what do you have in your ProgressChanged and RunWorkerCompleted event handlers?

-tg

----------


## cengineer

Ok thanks, I will move the addhandlers. The search function begins by calling
the main in my discover class which then creates threads to read in urls which each then crawls and parses and adds to a database. Pretty involved function from there which I am carefully stepping through now.



```
Private Sub Search(ByVal sender As Object, ByVal e As DoWorkEventArgs)
            Dim BlogDiscoverObj As New SearchBlogDiscovery.BlogDiscover
            Dim reply As String = Nothing
            Dim errormessage As String = Nothing

            Application.DoEvents()
            Try
                Console.WriteLine()
                Console.WriteLine()
                Console.Write(Thread.CurrentThread.Name & " ...searching " &   vbNewLine)
                BlogDiscoverObj.Main(connectionString, userAgent, fileName, clientName, clientProj)
                Dim i As Integer
                For i = 1 To 100
                    CType(sender, BackgroundWorker).ReportProgress(i)
                    Thread.Sleep(100)
                Next
                Console.ResetColor()
                Console.Write("Search Complete, Do you wish to generate queries, y or n? ")
                reply = Console.ReadLine()
                If reply = "y" Then
                    report()
                ElseIf reply = "n" Then
                    Console.Clear()
                    main()
                End If
            Catch ex As Exception
                errormessage = ex.Message

            End Try
        End Sub
```


my backgroundworker progress functions just have messages to the console to indicate what thread is doing...



```
Private Sub ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
            Console.WriteLine("Percent Complete: " & e.ProgressPercentage)

        End Sub
        Private Sub RunWorkerComplete(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
            Console.WriteLine("Background worker completed.")
        End Sub
```

Thank you for your response.

----------


## techgnome

you're doing user interaction in your threads:


```
                Console.ResetColor()
                Console.Write("Search Complete, Do you wish to generate queries, y or n? ")
                reply = Console.ReadLine()
```

Which defeats the purpose... running backgroundthreads should be standalone... and shouldn't be directly interacting with the user... 

Your use of the progress changed is useless too, since the query is already done by the time you fake the loop. 

also, is this an attempt to "restart" the application?:


```
                ElseIf reply = "n" Then
                    Console.Clear()
                    main()
```

Because if it is, you've just called your main function from inside your background thread.... 

It doesn't surprise me that it quits after a while... I'm surprised it isn't more catastrophic.

-tg

----------


## cengineer

Thanks again...always helpful

I have removed all user interaction from the search function ( backgroundworker process)  and checked other functions too, and assume that console error messages are ok. You mentioned that the progress changed event is used incorrectly so where would I insert that? I just need to be able to track the bgw so I can trace the process for errors. Pardon me for taking up much of your time, but dearly appreciated. I will make the changes and run it but apart from what you have noted, do you think that considering the design and intent of my app, am I at least headed in the right direction?

----------


## techgnome

hard to say... in this case, I wouldn't even bother with the progress changed event. create the thread, wire up the completed event, fire it off and let it do it's thing... when it's done, it fires off the completed event, and from there you do what ever cleanup you need to do... even if it's firing off a new thread (which, yes, you can do, we do that here to string together multiple BGW to pull data.) 

As for tracking errors... in the event of an error, you should be aborting the thread, which will cause the completed event to fire (in theory... I've heard rumors that it's not entirely reliable for some reason)... which will then have the aborted flag set to true. the reason I said the progress change is being misused is because it's a fake loop that's done after the search is done... so the progress it's reporting is junk, and you're sleeping the thread, which slows it down, and generally the purpose for BG Threads is to let time consuming processes a chance to run with out interefereing with the main thread... the sleep negates that. 

I don't know enough about what you are doing, but the way I would do it, is to create a class that holds the parameters needed to call the main funciton in your other class.... create an instance of it, fill it in, create a BGW, set the appropriate call backs, set the class as the parameter to the BGW and call the runasynch method. the run method then unpacks the parameter class, gets the data from it, creates the  BlogDiscoverObj object, and calls the appropriate method.  When it's done, set the object to nothing, sets up the return values, and then declares itself done.

I'm reviewing past threads and I'm not sure what gain you are getting with using the BGW either...  It looks like you're using threads for the sake of using them. if you were doing some kind of looping and running several searches simultaneously, then maybe... but it looks pretty sequential to me.

-tg

----------


## cengineer

I'm gonna go through this and see if I can implement it using this logic



> I don't know enough about what you are doing, but the way I would do it, is to create a class that holds the parameters needed to call the main funciton in your other class.... create an instance of it, fill it in, create a BGW, set the appropriate call backs, set the class as the parameter to the BGW and call the runasynch method. the run method then unpacks the parameter class, gets the data from it, creates the BlogDiscoverObj object, and calls the appropriate method. When it's done, set the object to nothing, sets up the return values, and then declares itself done.


But the objective of my app is to provide the user the following options:
1 - load a file to perform a search and let it run, the file can have up to 1 million urls.

2 - query the database with options to select items the user needs and return items instantly to the output window or to an output file


3 - perform a single url search by entering a single url


this is why I am using threads or bgw to perform option # 1 and then implement  later # 3.

I already have threads doing the url fetching and that works fine except for some synchronizing for the outputs I will figure out. But again you have been very helpful and I just wanted to make the context of the app clearer.

----------


## techgnome

Right... I get all that... but since it's a console app... it's not like the user can do anything else (like they would in a windows based app) and the UI isn't getting locked up (like it would in a windows app) ... so there isn't any benefit gain from using the BGW. 

-tg

----------


## cengineer

Sorry tg...I am required to migrate this to a forms app after I can effectively display the concurrent execution of the two main processes i.e search and queries..

In fact I have done the forms version first in what I would call beta version and I did not even use the bgw. Just called a new form when I needed to do option 2. Why they want me to do it this way...who knows??? 
but my sups argument is that this app will be migrated later and he wants the performance evaluated. So...thanks for all your time and assistance...

----------


## red7

Sir, 

Is it also possible if I trigger the .RunWorkerAsync() in the Timer event?

The idea is the event in the Do_Work automatically runs time to time..

Thanks. =)

----------


## jmcilhinney

> Sir, 
> 
> Is it also possible if I trigger the .RunWorkerAsync() in the Timer event?
> 
> The idea is the event in the Do_Work automatically runs time to time..
> 
> Thanks. =)


What happened when you tried?  If it worked then you have your answer.  If it failed then you need to tell us what happened so we can diagnose the issue.

----------


## red7

It Worked! ^_^ Thanks.

----------


## jmcilhinney

> It Worked! ^_^ Thanks.


Cool.  If it's feasible to do so, always try for yourself first.  Developing a "look first, ask questions later" attitude is important to becoming a good developer.

----------


## Roccoman

not &#37;100 sure this is the place for this - its a question about using the BackgroundWorker that is part of a class, not a form.



i have a class the processes a general tasks, *ClassA*.  it decides, based on info passed to it, which specific routine will handle this task.

i have another class that processes specific tasks and has functions that are called to handle the task.  call it *ClassB.ProcessJobFunction()*

this works fine, but this process can take a long time and i need to have a Form object display the current status ("processing item X of Y")

all of the examples of the BackgroundWorker use the BW as component on a form - in my case, i need it to be a member of my *ClassA*.

so when *ClassA* is told to process a job, it 
1) creates a backgroundworker to process the job
2) creates a new Form object to display the current tasks progress
3) receives notifications from *ClassB.ProcessJobFunction()*as progress is made
 - i had thought to have this function raise an event?
4) update the Form / UI

i tried using threading but it doesn't seem like the right tool.  BW does seem like the right tool but i am unclear if what i want is possible with it.

any feedback would be appreciated.

----------


## techgnome

using the BW IS threading... so it's either the right tool, or it isn't, but not both. The BW has a ProgressChange event that you can handle. That event would get raised on the UI thread, where you would then be able to update the display as needed. You can invoke the event when you want by calling .UpdateProgress method (I think that's right) from inside your process.

-tg

----------


## Roccoman

thanks for the quick response techgnome

yea i worded that badly - BW is threading of course.  i was refering to using either a Thread object or a BW object.

anyway i think i have found a suitable solution in the most unlikely of places: vb6 and *DoEvents*

i had forgotten that this was still in VB.NET (under *My.Application* and was reminded by a co-worker)

this allows the progress form to be updated and responsive to the user within the function *ClassB.ProcessJobFunction()* - and each thread has its own form so (in theory) there should be no cross-thread issues.

thanks

----------


## techgnome

The BW is simply a wrapper around the threading class... just depends on how much you want to black box (the BGW will hide some extraneous plumbing while dealing with the thread directly will give you finer control)... 

DoEvents.... Hmmm.... I'm not sure how I feel about that. It has its uses in VB6 mainly because VB6 didn't support threading. Which .NET does. Just because you CAN doesn't mean you SHOULD. I CAN shoot my foot with a  gun... doesn't mean it's a good idea. 

Each thread my have it's own form... but if I remember right, the process is still only going to have ONE UI thread... which means those extra forms may still be on the original thread. Point being, I don't think you're out of the woods. 

I'm not sure where the problem is. What you're doing is extremely typical and precisely what the BGW was designed for. That's why it has a ProgressChanged even that even includes the PercentCompleted in the event args. All you need to do it set the value and call the ProgressChanged method.  Then let the parent UI safely handle the UI update. 

-tg

----------


## Roccoman

the way i wrote the *ClassA* object it has a private member *FormWait* that is the progress form for that particular job.

there is a main form for the application but it is not the one that needs to be updated during the process - *ClassA* shows its own *FormWait* at the beginning of its processing and unloads it at the end.


i suppose the question is this: if i start a new thread (via a delegate subroutine) and that routine creates a new instance of a form, is that form in the new thread or the UI thread?

btw - i have run this a number of times now and so far have no cross-thread issues with the forms (other code is raising the issue, but that is due to shared functions being called)

anyway i truly do appreciate the responses - i am a new to threading and although devouring MSDN's Help system is useful, hearing from people who really use these tools helps a ton more.

----------


## jmcilhinney

Forms aren't "in" any particular thread.  Just like all data, a form is accessible on all threads.  The issue is that the handle of any control including a form, has an affinity for the thread it was created on.  That means that whatever thread creates the control owns the handle, which means that it's only safe to access members of that control, other than Invoke and the like, on that thread.

If you want to display a "Please Wait..." message to the user while a background operation takes place then I consider the best way to be as follows:

1. Display a form, modal or not, on the UI thread.  The form should provide no interface for closing it, other than a Cancel button if the operation can be cancelled.
2. Start a secondary thread, either explicitly or using a BackgroundWorker, in that form's Load or Shown event handler.
3. When the secondary thread completes, close the form.

----------


## Roccoman

> Forms aren't "in" any particular thread.  Just like all data, a form is accessible on all threads.  The issue is that the handle of any control including a form, has an affinity for the thread it was created on.  That means that whatever thread creates the control owns the handle, which means that it's only safe to access members of that control, other than Invoke and the like, on that thread.
> 
> If you want to display a "Please Wait..." message to the user while a background operation takes place then I consider the best way to be as follows:
> 
> 1. Display a form, modal or not, on the UI thread.  The form should provide no interface for closing it, other than a Cancel button if the operation can be cancelled.
> *2. Start a secondary thread, either explicitly or using a BackgroundWorker, in that form's Load or Shown event handler.*
> 3. When the secondary thread completes, close the form.


thats the problem - i need it to be the opposite.  i need my function to control its own form (as there can be multiple threads running at the same time, each with their own FormWait form)

perhaps my design is wrong in this.

you solution would work for me but would require a bit of re-work.

thanks for the feedback!

----------


## jmcilhinney

> thats the problem - i need it to be the opposite.  i need my function to control its own form (as there can be multiple threads running at the same time, each with their own FormWait form)


I doubt that you do.  What I described is most likely fine.  You should be able to show multiple forms on the UI thread and then have each of those start its own secondary thread.  Try the attached example.

----------


## Roccoman

thanks Jmc - i'll take a look a your sample

----------


## billboy

I have the following Sub that performs a couple of loops through a datatable . I currently have a progressbar1 that works fine, however while the sub is running if the user clicks on anything the progress bar and label freeze, the sub is still running and every functions fine. SO would I be correct in assuming this is a situation for backgroundworker? and have the label and progressbar woking on there own thread??

If so I am not sure how to implement it with my sub?? I am trying to follow and learn from the example you posted. I built the sample and trying to see how my code would be implemented.

I placed my Sub "GetValue()" in the BGW do work event but thats obviously not correct because that would just a one time event

I think I need to capture the first loop of that Sub

For i As Integer = 0 To dtlist.Rows.Count - 1
            Dim lat As Double = CDbl(dtlist.Rows(i)("Latitude"))
            Dim lon As Double = CDbl(dtlist.Rows(i)("Longitude"))



vb Code:
Dim Coords() As Coord = GetCoords()
        Dim sw As Stopwatch
        sw = Stopwatch.StartNew
        Me.propsprocessed.Visible = True
        Me.lblCount.Visible = True
        Me.ProgressBar1.Visible = True
         For i As Integer = 0 To dtlist.Rows.Count - 1
            Dim lat As Double = CDbl(dtlist.Rows(i)("Latitude"))
            Dim lon As Double = CDbl(dtlist.Rows(i)("Longitude"))
            'Labelcount
            Me.lblCount.Text = CStr(i + 1)
            Me.lblCount.Refresh()
            'progress bar
            ProgressBar1.Maximum = dtlist.Rows.Count
            ProgressBar1.Minimum = 0
            For d = ProgressBar1.Minimum To ProgressBar1.Maximum
                ProgressBar1.Value = i
            Next
            For t As Integer = 0 To dtsold.Rows.Count - 1
                dtsold.Rows(t)("Distance") = (DistanceCalc1(lat, lon, Coords(t).Lat1, Coords(t).Lon1, CChar("M")))
            Next
            Dim Dt As Decimal = NumericUpDown1.Value
            dtlist.Rows(i)("Value") = dtsold.Compute("Max(ClosePrice)", "Distance <=" & Dt & "")
         Next
        ProgressBar1.Visible = False
        sw.Stop()
        Dim StopWatchString As String
        StopWatchString = "Processing Time = " & sw.ElapsedMilliseconds & " milliseconds"
         Dim ts As String = CStr(sw.Elapsed.Minutes)
        ElapsedTime.Text = "In" & " " & ts & " " & "Seconds"
        ElapsedTime.Show()

If someone can give me some guideanceiwold appreciate it

Thanks

----------


## jmcilhinney

@billboy: It's very simple.  You perform the long-running task in the DoWork event handler.  If the long-running task is an entire loop then you put the entire loop in the DoWork event handler.  If you need to update the UI during the task then you call ReportProgress and handle the ProgressChanged event.  If you need to update the UI after the task then you handle the RunWorkerCompleted event.  That's really all there is to it.

----------


## billboy

I think I am a bit closer

getting error:
An unhandled exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll

Additional information: Exception has been thrown by the target of an invocation.

I put the task in the DoWorkEvent


vb Code:
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim worker As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
        Dim Coords() As Coord = GetCoords()
        Dim sw As Stopwatch
        sw = Stopwatch.StartNew
         For i As Integer = 0 To dtlist.Rows.Count - 1
            Dim lat As Double = CDbl(dtlist.Rows(i)("Latitude"))
            Dim lon As Double = CDbl(dtlist.Rows(i)("Longitude"))
            worker.ReportProgress(i)
             For t As Integer = 0 To dtsold.Rows.Count - 1
                dtsold.Rows(t)("Distance") = (DistanceCalc1(lat, lon, Coords(t).Lat1, Coords(t).Lon1, CChar("M")))
            Next
            Dim Dt As Decimal = NumericUpDown1.Value
            dtlist.Rows(i)("Value") = dtsold.Compute("Max(ClosePrice)", "Distance <=" & Dt & "")
         Next

The error comes up at the last line, what am I missing/doing wrong?

----------


## jmcilhinney

@billboy:

First things first, what's this doing in your DoWork event handler?

```
Dim Dt As Decimal = NumericUpDown1.Value
```

A NumericUpDown is a control.  No accessing controls in the DoWork event handler.

As for the error, that's the exception you see on the UI thread when an exception is thrown on a secondary thread.  You need to catch the exception on the secondary thread, examine it and fix the issue that's causing it, just as you would do on the UI thread.

----------


## billboy

Oh missed that NumericUpDown I took that out and hard coded my distance for now

As for catching the exception, I am not sure how to do that. The same code runs fine when not implementing backgroundworker

try
Catch ??

My Values are returned

----------


## jmcilhinney

> Oh missed that NumericUpDown I took that out and hard coded my distance for now
> 
> As for catching the exception, I am not sure how to do that. The same code runs fine when not implementing backgroundworker
> 
> try
> Catch ??
> 
> My Values are returned


There's only one way to catch an exception, and that's with a Catch statement.

----------


## billboy

Thats what I thought, I am not getting a message though?


vb Code:
Try
            For i As Integer = 0 To dtlist.Rows.Count - 1
                Dim lat As Double = CDbl(dtlist.Rows(i)("Latitude"))
                Dim lon As Double = CDbl(dtlist.Rows(i)("Longitude"))
                worker.ReportProgress(i)
                'Labelcount
                For t As Integer = 0 To dtsold.Rows.Count - 1
                    dtsold.Rows(t)("Distance") = (DistanceCalc1(lat, lon, Coords(t).Lat1, Coords(t).Lon1, CChar("M")))
                Next
                'Dim Dt As Decimal = NumericUpDown1.Value
                dtlist.Rows(i)("Value") = dtsold.Compute("Max(ClosePrice)", "Distance <=.5")
            Next
        Catch exc As Exception
            MessageBox.Show(exc.Message & vbCrLf & vbCrLf & exc.StackTrace, exc.GetType().ToString())
        End Try

Also tried it here:


vb Code:
Private Sub GetValue()
        Try
            Me.propsprocessed.Visible = True
            Me.lblCount.Visible = True
            Me.ProgressBar1.Visible = True
            Me.BackgroundWorker1.RunWorkerAsync()
        Catch exc As Exception
            MessageBox.Show(exc.Message & vbCrLf & vbCrLf & exc.StackTrace, exc.GetType().ToString())

And here:



vb Code:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GetValues.Click
        Try
            GetValue()
        Catch exc As Exception
            MessageBox.Show(exc.Message & vbCrLf & vbCrLf & exc.StackTrace, exc.GetType().ToString())
        End Try
    End Sub

----------


## billboy

Ok I still dont understand why my exception message box doesnt appear, but I managed to view the debug out window and found the error, i needed to set my progressbar maximum state

ProgressBar1.Maximum = dtlist.Rows.Count

I know I still have some problems, with access control textbox etc... but I think you have given me enough insight to tackle rest for now....

Thanks

----------


## jaminben

Hi,

Sorry for dragging this post back up but its the best example I found.

I'm also a bedroom hobbyist and therefore don't have any real expirence in programming so forgive me for if this is a dumb question.

I have a background worker within my form and a progress bar which works fine whilse the work being carried out is within the same form. If I move the work to a Module the work still gets carried out but my progress bar doesn't update anymore. My understanding is this is because the work and progress bar are not within the same ui thread but I dont understand how to fix this issue.

Here's a quick example of a test I setup...

My Main Form



```
Public Class Form_Test

    Delegate Sub SetLabelText_Delegate(ByVal Label As Label, ByVal [text] As String)

    Public Sub SetLabelText_ThreadSafe(ByVal Label As Label, ByVal [text] As String)

        If Label.InvokeRequired Then
            Dim MyDelegate As New SetLabelText_Delegate(AddressOf SetLabelText_ThreadSafe)
            Me.Invoke(MyDelegate, New Object() {Label, [text]})
        Else
            Label.Text = [text]
        End If

    End Sub

    Public Sub test()

        Dim i As Integer = 0

        Do While i < 20

            i = i + 1

            Me.BackgroundWorker1.ReportProgress(CInt((i / 20) * 100))
            Me.SetLabelText_ThreadSafe(Label1, "Same Form - " & FormatPercent(i / 20, 0))

            System.Threading.Thread.Sleep(100)

            Debug.Print("Running Test 2 From Within The Same Form: " & i)
        Loop

    End Sub

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

        Me.ProgressBar1.Value = e.ProgressPercentage

    End Sub

    Private Sub BackgroundWorker1_DoWork_1(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

        test()

    End Sub

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

        Me.BackgroundWorker1.RunWorkerAsync()

    End Sub

    Private Sub BackgroundWorker2_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker2.ProgressChanged

        Me.ProgressBar1.Value = e.ProgressPercentage

    End Sub

    Public Sub BackgroundWorker2_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker2.DoWork

        test_2()

    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click

        Me.BackgroundWorker2.RunWorkerAsync(2)

    End Sub

End Class
```

My Module Code



```
Module Module_Test

    Public Sub test_2()

        Dim i As Integer = 0

        Do While i < 20

            i = i + 1

            Form_Test.BackgroundWorker1.ReportProgress(CInt((i / 20) * 100))
            Form_Test.SetLabelText_ThreadSafe(Form_Test.Label1, "Module - " & FormatPercent(i / 20, 0))

            System.Threading.Thread.Sleep(100)

            Debug.Print("Running Test 2 From Within A Module: " & i)

        Loop

    End Sub

End Module
```

Anyone got any suggestions?

Many Thanks

Ben

----------


## jmcilhinney

@jaminben, the work is carried out on a different thread to the one that owns the ProgressBar in both cases.  That's the whole point.  The issue is related to your use of a default instance.  Follow the Blog link in my signature and check out my post on Default Form Instances to learn how they work and don't work.  That should help to explain what you're doing wrong.  If you still need help to fix it, post back.

----------


## jaminben

Can you throw me a bone (I've read through your blog, as well as others)... And I'm not really understanding instances and how you reference between them with the background worker.

Thanks

*Edit*

Not too worry I worked it out... thanks for the push in the right direction though  :Smilie:

----------


## tweakmaster

Thanks a lot. Great post!

----------


## BenJones

Thanks for shareing jmcilhinney, I not looked at the background worker, but your examples should help me a lot thanks agian.

----------


## Absolute_Zero

How can i access one or more control from DoWork event

vb Code:
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
         Dim strLines() As String = IO.File.ReadAllLines("some_path")
        Dim intLength As Integer = strLines.Length - 1 ' This will not less than 50,000
        Dim f() As String
         For j As Integer = 0 To intLength
            f = strLines(j).Split("|")
            ListView1.Items.Add(f(0))
            ListView2.Items.Add(f(1))
        Next
     End Sub

----------


## jmcilhinney

> How can i access one or more control from DoWork event


You can't.  That's what the ProgressChanged and RunWorkerCompleted events are for?  Did you actually read any of my posts?

----------


## akhileshbc

jm, all controls are in the UI thread. And thus, we can't access it from the BackgroundWorker's DoWork event, which runs in a separate thread.

But the variables inside that form(class level scope) is accessible inside it. Isn't it ?
I just tried it by declaring a class level array and inside the DoWork, I have returned the length of the array.
So, any variables declared in that current form is accessible, right?

Or that's not the best approach? I should always pass the values to it as a parameter of RunWorkerAsync() ?

Thanks  :wave:

----------


## jmcilhinney

> jm, all controls are in the UI thread. And thus, we can't access it from the BackgroundWorker's DoWork event, which runs in a separate thread.
> 
> But the variables inside that form(class level scope) is accessible inside it. Isn't it ?
> I just tried it by declaring a class level array and inside the DoWork, I have returned the length of the array.
> So, any variables declared in that current form is accessible, right?
> 
> Or that's not the best approach? I should always pass the values to it as a parameter of RunWorkerAsync() ?
> 
> Thanks


You're confusing two unrelated things.  The DoWork event handler of the BackgroundWorker is a method like any other other method.  It is a member of the form like any other form.  It has all the same rights and privileges as any other method in the form.  Member variables are within the scope of the form so any methods within that form can access those methods.

You can even write code in that method to access the controls on the form and the compiler will not complain as long as the syntax is correct.  If you were to call that method directly then the code would work fine.  It's only if, at run time, a method is run on a secondary thread that any control access that uses the Handle will fail.  That's a run time issue, not a design time issue.

----------


## akhileshbc

> You're confusing two unrelated things.  The DoWork event handler of the BackgroundWorker is a method like any other other method.  It is a member of the form like any other form.  It has all the same rights and privileges as any other method in the form.  Member variables are within the scope of the form so any methods within that form can access those methods.
> 
> You can even write code in that method to access the controls on the form and the compiler will not complain as long as the syntax is correct.  If you were to call that method directly then the code would work fine.  It's only if, at run time, a method is run on a secondary thread that any control access that uses the Handle will fail.  That's a run time issue, not a design time issue.


Means, the methods that access the controls can't be called inside the DoWork() as well as no controls can be accessed directly within that event.
Because, the code inside the DoWork() event executes in a separate thread and the controls are in another thread.

But all other variables/methods can directly be accessed within in it.

Am I correct ?

Thanks  :wave: 

*EDIT:*
jm, I am still confused(even after reading the below post). So, I will try to refresh my brain by reading again topics about Threading and thread affinity. And will create a thread in VB.Net forum, instead of flooding this thread  :Smilie:  Thanks again.

----------


## jmcilhinney

> Means, the methods that access the controls can't be called inside the DoWork() as well as no controls can be accessed directly within that event.
> Because, the code inside the DoWork() event executes in a separate thread and the controls are in another thread.
> 
> But all other variables/methods can directly be accessed within in it.
> 
> Am I correct ?
> 
> Thanks


No you're not correct.  Controls are accessed via member variables too.  All members are accessible from all other members.  Accessing a control in the DoWork event handler is allowed.  The compiler will not complain.  At run time though, those accesses that are performed via legal code will fail.  They are two different concepts: scope and thread affinity.

----------


## Tompkins

```
BackgroundWorker1_DoWork
        Dim worker As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
        Dim lines As String() = FileToArray(My.Computer.FileSystem.CurrentDirectory & "/filelist.txt")
        Dim line As String
        For Each line In lines
            uriSource = New Uri("http://localhost/" & line)
            uriPath = My.Computer.FileSystem.CurrentDirectory & line
            ???For i As Integer = 1 To 100
                worker.ReportProgress(i, "Downloading : " & line)
            ??????Next i
            downloading.DownloadFile(uriSource, uriPath)
        Next line
----------------
    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        Me.ProgressBar1.Value = e.ProgressPercentage
        Me.Label6.Text = TryCast(e.UserState, String)
    End Sub
```

i Would like to know how to make progress bar work with my "for each" line reader for downloading. for example how should i get BytesReceived .
or like 


```
         
ProgressBar1.Maximum = e.TotalBytesToReceive
ProgressBar1.Value = e.BytesReceived
```

thanks in advance!!

----------


## Tompkins

sry for duplicate post   :Frown:  website lagged

----------


## jmcilhinney

> ```
> BackgroundWorker1_DoWork
>         Dim worker As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
>         Dim lines As String() = FileToArray(My.Computer.FileSystem.CurrentDirectory & "/filelist.txt")
>         Dim line As String
>         For Each line In lines
>             uriSource = New Uri("http://localhost/" & line)
>             uriPath = My.Computer.FileSystem.CurrentDirectory & line
>             ???For i As Integer = 1 To 100
> ...


There are various options but the simplest is to just look at the name of the first parameter of the ReportProgress method: percentProgress.  Instead of setting the Maximum of the ProgressBar to the total number of bytes and the Value to the actual number of bytes, simply leave the Maximum as the default 100 and calculate the percentage yourself and pass that one value, e.g. if you have 5,000,000 bytes to download and you've downloaded 2,000,000 then the percentage is 40% so that's what you pass to ReportProgress.

----------


## Tompkins

> There are various options but the simplest is to just look at the name of the first parameter of the ReportProgress method: percentProgress.  Instead of setting the Maximum of the ProgressBar to the total number of bytes and the Value to the actual number of bytes, simply leave the Maximum as the default 100 and calculate the percentage yourself and pass that one value, e.g. if you have 5,000,000 bytes to download and you've downloaded 2,000,000 then the percentage is 40% so that's what you pass to ReportProgress.


How this should look like? at which point i should send that percentage with reportprogress in for each loop. can you show me some sample? Thanks for response!

----------


## jmcilhinney

> How this should look like? at which point i should send that percentage with reportprogress in for each loop. can you show me some sample? Thanks for response!


Anyone who has done primary school maths knows how to calculate a percentage so I'm not going to provide an example of that.  As for where to call ReportProgress, just ask yourself where in your code you want to update the ProgressBar and that's where you call ReportProgress.

----------


## Tompkins

> Anyone who has done primary school maths knows how to calculate a percentage so I'm not going to provide an example of that.  As for where to call ReportProgress, just ask yourself where in your code you want to update the ProgressBar and that's where you call ReportProgress.


 I want to update ProgressBar while downloading each file. For example its downloading one file then the progressbar fillsup, and then when it starts to download other file progress bar starts from begining just for different file size. As i can understand you are telling me the example for overall files being downloaded. Sorry for my bad english  :Frown: .. And thanks for your patience and help!


```
        Dim worker As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
        Dim lines As String() = FileToArray(My.Computer.FileSystem.CurrentDirectory & "/filelist.txt")
        Dim line As String
        Dim j As Integer
        Dim percent As Short
        For Each size In sizes
            Dim i As Integer = Convert.ToInt32(size)
            j = j + i
        Next size
        For Each line In lines
            Console.WriteLine(line)
            uriSource = New Uri("http://localhost/" & line)
            uriPath = My.Computer.FileSystem.CurrentDirectory & line
            worker.ReportProgress(percent, "Downloading : " & line)
            downloading.DownloadFile(uriSource, uriPath)
            Dim info As New FileInfo(My.Computer.FileSystem.CurrentDirectory & line)
            Dim length As Long = info.Length
            Dim g As Long
            g = g + length
            percent = (g * 100) / j
        Next line
```

this is for overall. it works, but what about each file Thank You!

----------


## peymanebrahimi

Hi John,
Thanks for useful explanation.
What about showing a message in another form, such as a none BorderStyleForm with a pic on it saying "please wait" or "loading" during the progress and closing the form after completion?

----------


## ident

With so many current BGW threads i think this should be on page One.

----------


## techgnome

Cross thread operation error...


Ident, you should know better than that... you know you can't access the UIThread from the BGW directly... it has to be invoked and passed back to the main UI processing thread... THEN you can get it to show up on the main form (Page1)...

-tg

----------


## Niya

Took me a while to catch that one...has me looking on page 1 for ident's post rofl

----------


## ident

> Took me a while to catch that one...has me looking on page 1 for ident's post rofl


90% of me says *techgnome* 	 is making a joke "thread" related, the rest is left a little confused if not  :Big Grin:

----------

