Invoking a function from within a class...

  • Thread starter hurricane_number_one
  • Start date
H

hurricane_number_one

I'm trying to have a class, which uses threads be able to raise events
to the form that created it. I've seen solutions around the net for
this, but I didn't really like their implementation. Most involve
passing the form into the class, or require a lot of coding. All I
really need to do is be able to have my thread call a function within
that class which runs on the same thread as the class. I've done this
from within forms, but can't figure out how to do it within a class
(see my comment below). How do I invoke the function from the thread
that the class is created on? I don't want the form to have to invoke
it. Any suggestions?

Public Class myClass

Dim myThread As Thread

Private client As Socket

Public Sub start()

myThread = New Thread(AddressOf threadFun)
myThread .Start()

End Sub

Private Sub threadFun()

raiseThisEvent(CLASS_EVENTS.START)

End Sub

Delegate Sub thisEventDelegate(ByVal thisEvent As CLASS_EVENTS)

Public Sub raiseThisEvent(ByVal thisEvent As CLASS_EVENTS)

if thisEvent = CLASS_EVENTS.START then
RaiseEvent onStart()
end if

End Sub

Public Sub raiseClassEvent(ByVal thisEvent As CLASS_EVENTS)

Dim passDelegate As New thisEventDelegate(AddressOf
raiseThisEvent)

' **** This is what I'd do if it were in a form, how do I do
the same within a class?? ****
Me.Invoke(passDelegate, thisEvent)
' ****

End Sub

end class
 
H

hurricane_number_one

Thanks, but I think I may be a bit unclear as to how to use this (I'm
new to .NET). In your code, what calls the InvokeADelegate function?
What is the delegate that gets passed in? Could you provide an
example of how this is called?

What happens if the syncObject doesn't implement the delegate
function? Using this, wouldn't the form need to implement every event
that the class raises?

Is there any simpler way to just get the class to call a function from
within a thread that can raise an event from the same thread as the
caller?

If the thread is just raising events that basically pass status
messages back to the form, does this really need to be thread safe?
What's the dangers that all of this is protecting me from?

I wonder if I should just have the thread set flags as to the state of
the object (i.e. connected, disconnected, err, ect) and have the main
form use a timer to just poll the object flag and update the UI when
the state changes?

Thanks for your help!!
 
T

Tom Shelton

Thanks, but I think I may be a bit unclear as to how to use this (I'm
new to .NET).  In your code, what calls the InvokeADelegate function?
What is the delegate that gets passed in?  Could you provide an
example of how this is called?

What happens if the syncObject doesn't implement the delegate
function?  Using this, wouldn't the form need to implement every event
that the class raises?

Is there any simpler way to just get the class to call a function from
within a thread that can raise an event from the same thread as the
caller?

If the thread is just raising events that basically pass status
messages back to the form, does this really need to be thread safe?
What's the dangers that all of this is protecting me from?

I wonder if I should just have the thread set flags as to the state of
the object (i.e. connected, disconnected, err, ect) and have the main
form use a timer to just poll the object flag and update the UI when
the state changes?

Thanks for your help!!




- Show quoted text -

Ok... here is a complete working example. The form, is simply a form
with a ListBox on it named uxpOutput. It has it's IntegralHeight
property set to false and it is docked to fill the form:

Option Strict On
Option Explicit On
Option Infer Off


Public Class MainForm
Private _t As Worker
Private Sub MainForm_Load(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles MyBase.Load
_t = New Worker(Me)
AddHandler _t.Event1, AddressOf Event1
AddHandler _t.Event2, AddressOf Event2
AddHandler _t.event3, AddressOf Event3
_t.Start()
End Sub

Private Sub Event1(ByVal sender As Object, ByVal e As EventArgs)
uxpOutput.Items.Add("Event1 Called")
End Sub
Private Sub Event2(ByVal sender As Object, ByVal e As EventArgs)
uxpOutput.Items.Add("Event2 Called")
End Sub
Private Sub Event3(ByVal sender As Object, ByVal e As EventArgs)
uxpOutput.Items.Add("Event3 Called")
End Sub

Private Sub MainForm_FormClosing(ByVal sender As System.Object,
ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles
MyBase.FormClosing
_t.Stop()
End Sub
End Class

Here is the Worker definition:

Option Strict On
Option Explicit On
Option Infer Off

Imports System
Imports System.ComponentModel
Imports System.Threading

Public Class Worker
Private _syncObject As ISynchronizeInvoke
Private _runner As Thread
Private _cancel As Boolean

Public Sub New(ByVal syncObject As ISynchronizeInvoke)
_syncObject = syncObject
End Sub

Public Event Event1 As EventHandler
Public Event Event2 As EventHandler
Public Event Event3 As EventHandler

Public Sub [Start]()
If Not _cancel Then
_runner = New Thread(AddressOf DoWork)
_runner.Start()
End If
End Sub

Public Sub [Stop]()
_cancel = True
_runner.Join()
End Sub

Private Sub DoWork()
Dim i As Integer
Dim r As New Random()

Do Until _cancel
i = r.Next(1, 31)
Select Case i
Case 1 To 10
RaiseAnEvent(Event1Event, New Object() {Me, New
EventArgs()})
Case 11 To 20
RaiseAnEvent(Event2Event, New Object() {Me, New
EventArgs()})
Case 21 To 30
RaiseAnEvent(Event3Event, New Object() {Me, New
EventArgs()})
End Select
Thread.Sleep(1000)
Loop
End Sub

Private Sub RaiseAnEvent(ByVal d As [Delegate], ByVal args() As
Object)
If Not d Is Nothing Then
If _syncObject Is Nothing Or Not
_syncObject.InvokeRequired Then
d.Method.Invoke(d.Target, args)
Else
_syncObject.Invoke(d, args)
End If
End If
End Sub

End Class

Anyway, if you comment out the addhandler statements, you will see
that only the events you subscribe to are raised - and they are raised
on the right thread :)

HTH
 
H

hurricane_number_one

Thanks for your help, I'll give that a shot.

Thanks, but I think I may be a bit unclear as to how to use this (I'm
new to .NET).  In your code, what calls the InvokeADelegate function?
What is the delegate that gets passed in?  Could you provide an
example of how this is called?
What happens if the syncObject doesn't implement the delegate
function?  Using this, wouldn't the form need to implement every event
that the class raises?
Is there any simpler way to just get the class to call a function from
within a thread that can raise an event from the same thread as the
caller?
If the thread is just raising events that basically pass status
messages back to the form, does this really need to be thread safe?
What's the dangers that all of this is protecting me from?
I wonder if I should just have the thread set flags as to the state of
the object (i.e. connected, disconnected, err, ect) and have the main
form use a timer to just poll the object flag and update the UI when
the state changes?
Thanks for your help!!
On Jun 25, 8:56 pm, Tom Shelton <[email protected]>
wrote:
- Show quoted text -

Ok... here is a complete working example.  The form, is simply a form
with a ListBox on it named uxpOutput.  It has it's IntegralHeight
property set to false and it is docked to fill the form:

Option Strict On
Option Explicit On
Option Infer Off

Public Class MainForm
    Private _t As Worker
    Private Sub MainForm_Load(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles MyBase.Load
        _t = New Worker(Me)
        AddHandler _t.Event1, AddressOf Event1
        AddHandler _t.Event2, AddressOf Event2
        AddHandler _t.event3, AddressOf Event3
        _t.Start()
    End Sub

    Private Sub Event1(ByVal sender As Object, ByVal e As EventArgs)
        uxpOutput.Items.Add("Event1 Called")
    End Sub
    Private Sub Event2(ByVal sender As Object, ByVal e As EventArgs)
        uxpOutput.Items.Add("Event2 Called")
    End Sub
    Private Sub Event3(ByVal sender As Object, ByVal e As EventArgs)
        uxpOutput.Items.Add("Event3 Called")
    End Sub

    Private Sub MainForm_FormClosing(ByVal sender As System.Object,
ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles
MyBase.FormClosing
        _t.Stop()
    End Sub
End Class

Here is the Worker definition:

Option Strict On
Option Explicit On
Option Infer Off

Imports System
Imports System.ComponentModel
Imports System.Threading

Public Class Worker
    Private _syncObject As ISynchronizeInvoke
    Private _runner As Thread
    Private _cancel As Boolean

    Public Sub New(ByVal syncObject As ISynchronizeInvoke)
        _syncObject = syncObject
    End Sub

    Public Event Event1 As EventHandler
    Public Event Event2 As EventHandler
    Public Event Event3 As EventHandler

    Public Sub [Start]()
        If Not _cancel Then
            _runner = New Thread(AddressOf DoWork)
            _runner.Start()
        End If
    End Sub

    Public Sub [Stop]()
        _cancel = True
        _runner.Join()
    End Sub

    Private Sub DoWork()
        Dim i As Integer
        Dim r As New Random()

        Do Until _cancel
            i = r.Next(1, 31)
            Select Case i
                Case 1 To 10
                    RaiseAnEvent(Event1Event, New Object() {Me, New
EventArgs()})
                Case 11 To 20
                    RaiseAnEvent(Event2Event, New Object() {Me, New
EventArgs()})
                Case 21 To 30
                    RaiseAnEvent(Event3Event, New Object() {Me, New
EventArgs()})
            End Select
            Thread.Sleep(1000)
        Loop
    End Sub

    Private Sub RaiseAnEvent(ByVal d As [Delegate], ByVal args() As
Object)
        If Not d Is Nothing Then
            If _syncObject Is Nothing Or Not
_syncObject.InvokeRequired Then
                d.Method.Invoke(d.Target, args)
            Else
                _syncObject.Invoke(d, args)
            End If
        End If
    End Sub

End Class

Anyway, if you comment out the addhandler statements, you will see
that only the events you subscribe to are raised - and they are raised
on the right thread :)

HTH
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top