Search code examples
.netvb.netcustom-events

Different ways of raising a Custom Event in .NET Framework


I know that in VB .Net it is possible to define your custom Event Handler.

This is a way for a class to know when another one is listening to its events. This example code comes from MSDN :

Private Events As EventHandlerList

Public Custom Event MyEvent As EventHandler
    AddHandler(value As EventHandler)
        Events.AddHandler("Test", value)
    End AddHandler

    RemoveHandler(value As EventHandler)
        Events.RemoveHandler("Test", value)
    End RemoveHandler

    RaiseEvent(sender As Object, e As EventArgs)
        CType(Events("Test"), EventHandler).Invoke(sender, e)
    End RaiseEvent
End Event

Now, this is how you can raise your custom event :

Private Sub MySub()
    RaiseEvent MyEvent(Me, EventArgs.Empty)
End Sub

So far so good, no problem at all.

My question is, since in my class I have a direct access to the EventHandlerList, can I call it outside the custom event handler ? And if I do, is there any difference between what this sub does from the one above ?

Private Sub MySub2()
    CType(Events("Test"), EventHandler).Invoke(Me, EventArgs.Empty)
End Sub

I know this probably is no good habits at all, I'm just curious as I may have a function that is passed an event name as String so that way of raising the event might work for me, I would do something like :

Private Sub RaiseCustomEvent(EventName As String, Ev as EventArgs)
    CType(Events(EventName), EventHandler).Invoke(Me, Ev)
End Sub

Solution

  • My question is, since in my class I have a direct access to the EventHandlerList, can I call it outside the custom event handler?

    Yes.

    And if I do, is there any difference between what this sub does from the one above?

    No. The RaiseEvent statement simply calls the RaiseEvent part of your event declaration. The VB.NET spec says:

    The RaiseEvent declaration takes the same parameters as the event delegate and will be called when a RaiseEvent statement is executed.

    Note, though, that the MSDN example is broken---it raises a NullReferenceException if no event handler is attached (Fiddle):

    Public Module Module1
        Public Sub Main()
            Dim x As New T()
            x.RaiseTestEvent()
        End Sub
    End Module
    
    Public Class T
        Private Events As New System.ComponentModel.EventHandlerList()
    
        Public Custom Event MyEvent As EventHandler
            AddHandler(value As EventHandler)
                Events.AddHandler("Test", value)
            End AddHandler
    
            RemoveHandler(value As EventHandler)
                Events.RemoveHandler("Test", value)
            End RemoveHandler
    
            RaiseEvent(sender As Object, e As EventArgs)
                CType(Events("Test"), EventHandler).Invoke(sender, e)
            End RaiseEvent
        End Event
    
        Public Sub RaiseTestEvent()
            ' Throws NullReferenceException if no event handler is attached.
            RaiseEvent MyEvent(Me, EventArgs.Empty)
        End Sub
    End Class
    

    For "regular" events, RaiseEvent is just a NO-OP if no handler is attached (Fiddle). The VB spec says:

    The RaiseEvent statement is processed as a call to the Invoke method of the event's delegate, using the supplied parameters, if any. If the delegate’s value is Nothing, no exception is thrown.