-
Using the BackgroundWorker Component
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 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
-
Passing Data to be Used in the Worker Thread.
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
-
Re: Using the BackgroundWorker Component
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
-
Re: Using the BackgroundWorker Component
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 filePath
End 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 = fileNames
End 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.
-
Re: Using the BackgroundWorker Component
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.
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by 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.
The error message says this:
Quote:
Modify WorkerReportsProgress to state that it does report progress.
In post #1 I said this:
Quote:
Set the BackgroundWorker's WorkerReportsProgress property to True.
In post #4 I said this:
Quote:
Note that for the first example to work the WorkerReportsProgress property must be set to True.
Are you noticing a theme here?
-
Re: Using the BackgroundWorker Component
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.
-
Re: Using the BackgroundWorker Component
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...
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by 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 ;)
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.
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by zxed
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.
-
Re: Using the BackgroundWorker Component
thanks for getting back to me., i will figure out the web service thingy, and create a sep thread with code + examples. :)
-
Re: Using the BackgroundWorker Component
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.
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by 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.
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.
-
Re: Using the BackgroundWorker Component
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by Xancholy
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.
-
Re: Using the BackgroundWorker Component
-
Re: Using the BackgroundWorker Component
doran, you're going to have to tidy that post up before I'll even consider looking at it.
-
Re: Using the BackgroundWorker Component
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.
-
Re: Using the BackgroundWorker Component
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 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
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 If
End 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 If
End 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.
-
Re: Using the BackgroundWorker Component
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by jmcilhinney
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 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
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...
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by numbskull77
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.
-
Re: Using the BackgroundWorker Component
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
Code:
bgwkdata.RunWorkerAsync()
and for stop button i have
Code:
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
Code:
If bgwkdata.CancellationPending Then
e.Cancel = True
Exit Sub
End If
Thanks :)
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by 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
Code:
bgwkdata.RunWorkerAsync()
and for stop button i have
Code:
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
Code:
If bgwkdata.CancellationPending Then
e.Cancel = True
Exit Sub
End If
Thanks :)
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.
-
Re: Using the BackgroundWorker Component
Hi John ,
here you what i have done
Code:
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 :
Code:
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
-
Re: Using the BackgroundWorker Component
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
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by
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
The location of the BW is this: System.ComponentModel.BackgroundWorker
So I would start by looking for it in the System.ComponentModel namespace
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by
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
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.
-
Re: Using the BackgroundWorker Component
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
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by
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
That is not the topic of this thread. You should ask such questions in new threads in the appropriate forum.
-
Re: Using the BackgroundWorker Component
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?
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by
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?
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.
-
Re: Using the BackgroundWorker Component
-
Re: Using the BackgroundWorker Component
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?)
Code:
Dim worker As backgroundWorker = DirectCast(sender, backgroundWorker)
entire code
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!
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by
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?)
Code:
Dim worker As backgroundWorker = DirectCast(sender, backgroundWorker)
entire code
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!
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.
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by
jmcilhinney
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!
-
Re: Using the BackgroundWorker Component
Excellent post! It has helped me a lot!! Keep up the always great work jmcilhinney!
-
Re: Using the BackgroundWorker Component
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.
Code:
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()
Code:
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
Code:
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.
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by
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.
Code:
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()
Code:
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
Code:
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.
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?
-
Re: Using the BackgroundWorker Component
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.
Code:
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.
-
Re: Using the BackgroundWorker Component
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
-
Re: Using the BackgroundWorker Component
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.
Code:
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...
Code:
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.
-
Re: Using the BackgroundWorker Component
you're doing user interaction in your threads:
Code:
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?:
Code:
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
-
Re: Using the BackgroundWorker Component
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?
-
Re: Using the BackgroundWorker Component
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
-
Re: Using the BackgroundWorker Component
I'm gonna go through this and see if I can implement it using this logic
Quote:
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.
-
Re: Using the BackgroundWorker Component
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
-
Re: Using the BackgroundWorker Component
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...
-
Re: Using the BackgroundWorker Component
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. =)
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by
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. =)
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.
-
Re: Using the BackgroundWorker Component
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by
red7
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.
-
Re: Using the BackgroundWorker Component
not %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.
-
Re: Using the BackgroundWorker Component
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
-
Re: Using the BackgroundWorker Component
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
-
Re: Using the BackgroundWorker Component
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
-
Re: Using the BackgroundWorker Component
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.
-
Re: Using the BackgroundWorker Component
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.
-
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by
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.
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!
-
1 Attachment(s)
Re: Using the BackgroundWorker Component
Quote:
Originally Posted by
Roccoman
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.