Delegates and Events in Visual Basic
Delegates and events are fundamental concepts in object-oriented programming, particularly in event-driven applications like those built with Visual Basic. They provide a powerful mechanism for implementing the publish-subscribe pattern, allowing objects to communicate with each other without direct coupling.
Understanding Delegates
A delegate in Visual Basic is a type that represents references to methods with a particular parameter list and return type. Think of it as a type-safe function pointer. Delegates are declared using the Delegate
keyword.
Delegate Declaration
The syntax for declaring a delegate is as follows:
Delegate Sub MyDelegate(ByVal message As String)
' Or for a function:
' Delegate Function Calculate(ByVal a As Integer, ByVal b As Integer) As Integer
This declares a delegate named MyDelegate
that can point to any method that takes a single String
argument and returns Sub
(void).
Instantiating and Using Delegates
Once a delegate type is declared, you can create instances of it and assign methods to them. The methods assigned must match the signature of the delegate.
' Assume MyMethod1 and MyMethod2 have the correct signature
Public Class MyClass
' Declare a delegate instance
Public WithEvents Handler As MyDelegate
Public Sub New()
' Assign a method to the delegate
AddHandler Handler, AddressOf MyMethod1
' Or directly: Handler = New MyDelegate(AddressOf MyMethod1)
End Sub
' A method that matches the delegate signature
Private Sub MyMethod1(ByVal message As String)
Console.WriteLine($"Method 1 received: {message}")
End Sub
Private Sub MyMethod2(ByVal message As String)
Console.WriteLine($"Method 2 received: {message}")
End Sub
Public Sub TriggerEvent(ByVal text As String)
' Invoke the delegate (which invokes the assigned methods)
If Handler IsNot Nothing Then
Handler(text)
End If
End Sub
End Class
Understanding Events
An event is a mechanism by which a class (the publisher) can notify other classes (the subscribers) when something significant happens. Events are built upon delegates. A class that raises an event declares a delegate and then declares an event using that delegate type.
Event Declaration
The Event
keyword is used to declare an event. It is typically declared as Public
to allow other objects to subscribe to it.
Public Class Publisher
' Declare the delegate for the event
Public Delegate Sub DataChangedEventHandler(ByVal sender As Object, ByVal e As EventArgs)
' Declare the event using the delegate
Public Event DataChanged As DataChangedEventHandler
' Alternative using a generic event handler:
' Public Event DataChanged As EventHandler(Of EventArgs)
Private _data As String
Public Property Data() As String
Get
Return _data
End Get
Set(Value As String)
If _data <> Value Then
_data = Value
' Raise the event when data changes
OnDataChanged(EventArgs.Empty)
End If
End Set
End Property
Protected Overridable Sub OnDataChanged(ByVal e As EventArgs)
' Check if there are any subscribers before raising the event
RaiseEvent DataChanged(Me, e)
End Sub
End Class
Subscribing to an Event
Other classes can subscribe to an event using the AddHandler
statement. The method that handles the event must match the delegate's signature.
Public Class Subscriber
Public Sub New(ByVal publisher As Publisher)
' Subscribe to the DataChanged event
AddHandler publisher.DataChanged, AddressOf Me.HandleDataChange
End Sub
' Event handler method
Private Sub HandleDataChange(ByVal sender As Object, ByVal e As EventArgs)
Console.WriteLine("Data has changed!")
' You can also cast sender to Publisher to access its properties
Dim pub As Publisher = CType(sender, Publisher)
Console.WriteLine($"New data: {pub.Data}")
End Sub
' To unsubscribe:
' RemoveHandler publisher.DataChanged, AddressOf Me.HandleDataChange
End Class
Key Concepts and Best Practices
- Type Safety: Delegates ensure type safety by guaranteeing that the assigned methods have the correct parameters and return type.
- Decoupling: Events and delegates promote loose coupling between objects. The publisher doesn't need to know about the specific subscribers, and subscribers don't need direct references to the publisher's internal methods.
WithEvents
Keyword: When declaring an event field within a class, usingWithEvents
automatically creates an event handler mechanism.RaiseEvent
Statement: This statement is used to trigger an event. It's good practice to check if the event has any subscribers (i.e., if the delegate is notNothing
) before raising it.EventArgs
: Custom classes can inherit fromEventArgs
to pass additional information with an event.- Standard Event Pattern: The common practice is to have an
OnEventName
protected virtual method that raises the event. This allows derived classes to intercept or modify event handling.
Note on Generics:
Starting with .NET Framework 3.5, you can use the generic EventHandler(Of TEventArgs)
delegate, which often simplifies event declarations and usage, especially when custom data needs to be passed.
' Declaration
Public Event MyCustomEvent As EventHandler(Of MyCustomEventArgs)
' Raising
Protected Overridable Sub OnMyCustomEvent(ByVal e As MyCustomEventArgs)
RaiseEvent MyCustomEvent(Me, e)
End Sub
' Handler
Private Sub HandleMyCustomEvent(sender As Object, e As MyCustomEventArgs)
' Access e.CustomProperty
End Sub
By mastering delegates and events, you can build more robust, scalable, and responsive applications in Visual Basic.