BackgroundWorker from a class

etwombly

Member
Joined
Jun 8, 2007
Messages
9
Programming Experience
1-3
I'm trying to show a progress bar on my main form, however the calculation that would update the form is in a separate class.

I have all the DoWork events and all on my main form code, and the call to the class where my calculation is done is within the DoWork, however I don't know how to trigger the form events within the class. Do you have to pass something by reference to the class object? I tried passing the BackgroundWorker itself but that didn't do anything.

Any ideas, or is this impossible?
 
My initial thought was that you should have the class expose a progress event, the form using this class would also use the progress event to present the progress to the UI. If I understood your setup the BackgroundWorker in the class would ReportProgress from its DoWork, then class would use this to raise its own Progress event.
 
So, bear with me on this...

I would create a BackGroundWorker in both my class and my form. Then, in the DoWork in my class, I would call ReportProgress, and then in the ProgressChanged event, do something like this:


Protected Overridable Sub OnProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)

RaiseEvent ProgressChanged(sender, e)

End Sub

If this is right, how will that event be able to be triggered from my main form?

My main form(within the DoWork) is essentially...

myClass.Run()

Will this sub trigger the ProgressChanged on my main form as well?
 
Why do you need 2 BGWorkers? Now I for sure don't understand you setup :confused:

If you simply don't know how to declare an event, it is done so:
Public Event myprogress(ByVal indicator As Integer)

Then you would raise it from the class:
RaiseEvent myprogress(123)
 
Sorry, i'm still trying to figure out the BackgroundWorker things on my own. There shouldn't be two, just the one worker on the main form.

I declared the event, and I raised it in the code of my class, but I'm not sure how to catch that event being raised in the main form.
 
There are 2 ways to use events of an object, either declare the instance variable WithEvents and select the event like you do with control instances (the handler method skeleton is written for you with the Handles clause), or add event handler dynamically with the AddHandler statement.
 
If you Raise the event directly from DoWork, you might get an error about attempting to update a control froma thread other than the thread it was created on. If you do, return here for more advice..
 
Yes, like I said (tried to) use bgw.ReportProgress and raise the classes own progress event from bgw.ProgressChanged , the bgw.ProgressChanged event is thread-safe. Internally bgw uses AsyncOperationManager/AsyncOperation class to achieve this.
 
Actually, I did have a problem with the thread-safetey issue.

Let me try to be a little more clear...

Main form(the general idea):

Private Sub DoWork()

Dim myVar as New MyClass()
AddHandler myVar.ProgressChanged, AddressOf backgroundWorker1_ProgressChanged

myVar.Run()

End Sub

Private Sub BackgroundWorker1_ProgressChanged(sender, e)

'Update Labels and progress bar

End Sub


MyClass:

Public Event ProgressChanged As ProgressChangedEventHandler

Public Sub Run()

'Do Calculations
OnProgressChanged(..,..)

End Sub

Overridable Sub OnProgressChanged(ByVal e As ProgressChangedEventArgs)

RaiseEvent ProgressChanged(Me, e)

End Sub


I'm not sure what you mean JohnH, I don't really understand VS.NET threading all that well yet. Either way, if I don't turn off the flag for my labels, it gives me the cross-thread error.
 
I don't understand that, but here is an example that runs without cross-threading issues:
VB.NET:
Imports System.ComponentModel
Class something

    Public Event ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)

    Public Sub New()
        bgw.WorkerReportsProgress = True
    End Sub

    Public Function run() As Boolean
        If bgw.IsBusy Then
            Return False
        Else
            bgw.RunWorkerAsync()
            Return True
        End If
    End Function

    Private WithEvents bgw As New System.ComponentModel.BackgroundWorker

    Private Sub bgw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles bgw.DoWork
        For i As Integer = 1 To 10
            Threading.Thread.Sleep(500)
            bgw.ReportProgress(i)
        Next
    End Sub

    Private Sub bgw_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles bgw.ProgressChanged
        RaiseEvent ProgressChanged(Me, e)
    End Sub

End Class
Example usage:
VB.NET:
Private WithEvents s As New something

Private Sub s_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles s.ProgressChanged
    Me.Label1.Text = e.ProgressPercentage
End Sub

Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
    s.run()
End Sub
 
Back
Top