Delegates, Events and the Observer Pattern

14.1 Delegates

Public Delegate Function Validator(Of T)(value As T) As Boolean
Dim notEmpty As Validator(Of String) = Function(s) Not String.IsNullOrWhiteSpace(s)

Dim transform As Func(Of String, String) = AddressOf String.Copy
Dim print As Action(Of String) = AddressOf Console.WriteLine
Dim isPositive As Predicate(Of Integer) = Function(n) n > 0
Dim byLength As Comparison(Of String) = Function(a, b) a.Length.CompareTo(b.Length)

Dim pipeline As Func(Of Integer, Integer) = Function(x) x + 1
pipeline = Function(x) pipeline.Invoke(x) * 2          ' careful: recursion! capture in a local first

14.2 Events: Standard Pattern

Public Class OrderPlacedEventArgs
    Inherits EventArgs
    Public ReadOnly Property OrderId As Integer
    Public Sub New(orderId As Integer)
        Me.OrderId = orderId
    End Sub
End Class

Public Class OrderService
    Public Event OrderPlaced As EventHandler(Of OrderPlacedEventArgs)
    Protected Overridable Sub OnOrderPlaced(e As OrderPlacedEventArgs)
        RaiseEvent OrderPlaced(Me, e)          ' RaiseEvent is null-safe
    End Sub
    Public Sub PlaceOrder(id As Integer)
        ' ... save ...
        OnOrderPlaced(New OrderPlacedEventArgs(id))
    End Sub
End Class

14.3 Subscribing

' Declarative
Private WithEvents _orders As New OrderService()
Private Sub Orders_Placed(sender As Object, e As OrderPlacedEventArgs) Handles _orders.OrderPlaced
    Console.WriteLine($"Order {e.OrderId} placed")
End Sub

' Dynamic
Dim svc As New OrderService()
Dim handler As EventHandler(Of OrderPlacedEventArgs) = Sub(s, e) Console.WriteLine(e.OrderId)
AddHandler svc.OrderPlaced, handler
RemoveHandler svc.OrderPlaced, handler          ' avoid leaks: unsubscribe long-lived publishers

14.4 Custom Events and Weak Events

Custom Event with AddHandler/RemoveHandler/RaiseEvent blocks for custom storage, thread safety, or WPF CommandManager forwarding.

Weak event patterns (WeakReference, WPF WeakEventManager) prevent publishers from keeping subscribers alive.

Modern alternatives: IObservable(Of T) / Reactive Extensions (System.Reactive), and mediator/message buses (MediatR, WeakReferenceMessenger from CommunityToolkit.Mvvm).