Pauli Price
Pauli Price

Reputation: 4237

Class level, rather than instance, handling of custom events?

Is there some way for the main form to listen for any raise of a custom event of ClassB without reference to the specific instance of ClassB that raised the event?

The instance of ClassB that would generate the event is currently anonymously instantiated inside the ClassA instance the form knows.

(Final update: The reason my direct calls to MainForm methods didn't work as I expected is in the accepted answer to this question. )

Update I suspect that it's more complicated than I thought. The following quote explains why my call to MainForm.DataReady() didn't work - in a maddeningly obscure fashion.

The magic of .NET events hides the fact that, when you subscribe to an event in an instance of B by an instance of A, A gets sent over into B's appdomain. If A isn't MarshalByRef, then a value-copy of A is sent. Now you've got two separate instances of A, which is why you experienced the unexpected behaviors.

Cross AppDomain MarshallByRef vs value copy discussion

Update2:

Using:

Debug.WriteLine("SetWaitState executing with Id={0}", AppDomain.CurrentDomain.Id)

while executing MainForm.DataReady() in context of a MainForm local event handler and while called from ClassB showed they were running in the same AppDomain each time. That leaves different threads as the reason for the problem -- and yet MainForm.InvokeRequired returned false in each case. It still doesn't make sense -- but at least the custom events -- bubbled up, as necessary -- did work.

Code below illustrates the relationships.


Class MainForm
  private A as New ClassA

  private sub getData
    A.getData() 'Sets up the com object & callback
  end sub

  Private Sub _ClassB_HandleEvent(ResultMessage As String) Handles {some static/shared reference to ClassB}.CustomEvent
     'do something with the Message
  End Sub

End Class

Class ClassA

  public sub getData()
     Dim ComObj as New ComObject
     Call ComObj.setClient(New ClassB)
  End Sub

End Class

Class ClassB
  Implements IComObjectClient
  Public Event CustomEvent(ByVal ResultMessage As String)

  sub getdata_callback(results() as Object) handles IComObjectClient.getdata_callback
    ' Get the results
    RaiseEvent CustomEvent("Got Data") 'because calling MainForm.DataReady() doesn't work 
  end sub

End Class

Upvotes: 2

Views: 299

Answers (2)

PGallagher
PGallagher

Reputation: 3113

Or ignore Delegates all together, and just capture the Class B Event in Class A, and Raise a New Class A Event which your Main Sub can hook up too...

Something Like...

    Class MainForm
        private A As ClassA

        Public Sub _ClassB_HandleEvent(ByVal ResultMessage As String)
            ' Do Something like.... TextBox1.Text &= ("Received Event Saying - " & ResultMessage) & vbCrLf
        End Sub

        Private Sub GetData()
            A = New ClassA
            AddHandler A.GotDataFromClassB, AddressOf _ClassB_HandleEvent
            A.GetData()
        End Sub
    End Class

    Public Class ClassA
        Public Event GotDataFromClassB(ByVal ResultMessage As String)
        Private B As ClassB

        Public Sub GetData()
            B = New ClassB
            AddHandler B.CustomEvent, Sub(ResultMessage As String)
                                                RaiseEvent GotDataFromClassB(ResultMessage)
                                      End Sub
            Dim ComObj as New ComObject
            Call ComObj.setClient(B)
        End Sub
    End Class

Class ClassB
  Implements IComObjectClient
  Public Event CustomEvent(ByVal ResultMessage As String)

  sub getdata_callback(results() as Object) handles IComObjectClient.getdata_callback
    ' Get the results
    RaiseEvent CustomEvent("Got Data")
  end sub
End Class

Upvotes: 1

Conrad Frix
Conrad Frix

Reputation: 52675

Is there some way for the main form to listen for any raise of a custom event of ClassB without reference to the specific instance of ClassB that raised the event?

You can but you'd have to

  1. Declare a Public CustomEventHandler Delegate
  2. Declare a ClassB variable so you can add the handler
  3. Pass a handler from MainFrom into Class A

e.g.

Public Class MainForm

    Private Sub _ClassB_HandleEvent(ByVal ResultMessage As String)
      'do something with the Message
    End Sub

    Private A As New ClassA

    Public Sub getData()

        Dim eh As New ClassB.CustomEventHandler(AddressOf _ClassB_HandleEvent) 'create the delegate
        A.getData(eh) 'Pass it to ClassA
    End Sub
End Class


Public Class ClassA

    Public Sub getData(ByVal eh As ClassB.CustomEventHandler)
        Dim b As New ClassB
        AddHandler b.CustomEvent, eh
        Call setClient(b)
    End Sub

    Public Sub setClient(ByVal b As ClassB)
        b.getdata_callback()
    End Sub

End Class

Public Class ClassB
    Delegate Sub CustomEventHandler(ByVal ResultMessage As String) 'Declare the handler
    Public Event CustomEvent As CustomEventHandler

    Sub getdata_callback()
        RaiseEvent CustomEvent("Got Data")
    End Sub

End Class

Upvotes: 0

Related Questions