100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Events and Delegates in VB.NET

Understand how delegates provide type-safe function references in VB.NET, and how the Event/RaiseEvent/WithEvents system builds the observer pattern on top of them.

.NET IntegrationIntermediate9 min readJul 10, 2026
Analogies

Understanding Delegates

A delegate in VB.NET is a type-safe reference to a method, declared with the Delegate keyword — for example, Public Delegate Sub NotifyHandler(message As String) defines a delegate type that can point to any Sub matching that exact signature. Once declared, you can create a variable of that delegate type, assign it a method using AddressOf, and invoke it as if it were a method call; delegates are the mechanism underlying every event in .NET, and they're what makes callbacks and event handlers possible without resorting to unsafe function pointers.

🏏

Cricket analogy: A delegate is like a designated 12th man contract that specifies the exact role (fielding substitute) — any player assigned to it must fit that precise role, just as any method assigned to a delegate must match its exact signature.

Defining and Raising Custom Events

vbnet
Public Class Thermostat
    Public Event TemperatureChanged(sender As Object, newTemp As Double)

    Private _temp As Double
    Public Sub SetTemperature(value As Double)
        _temp = value
        RaiseEvent TemperatureChanged(Me, _temp)
    End Sub
End Class

The Event keyword declares a member that other code can subscribe to, and internally the compiler generates a multicast delegate to hold the list of subscribers. Inside the class that owns the event, RaiseEvent fires it, invoking every subscribed handler in turn with the arguments supplied; outside code cannot call RaiseEvent directly — it can only subscribe with AddHandler or (for WithEvents fields) the Handles clause — which enforces the one-way notification model where only the publisher decides when the event fires.

🏏

Cricket analogy: RaiseEvent firing to every subscriber is like a stadium's PA announcer broadcasting a wicket to every fan simultaneously — each listener reacts independently to the same single announcement.

Handling Events with WithEvents and Handles

VB.NET offers a distinctive way to subscribe to events declaratively: declaring a field with WithEvents, as in Private WithEvents _thermo As New Thermostat(), lets any Sub in that class attach itself with a Handles clause, such as Private Sub OnTempChanged(...) Handles _thermo.TemperatureChanged. This binding is resolved at compile time and remains fixed for the lifetime of the object referenced by that field, whereas reassigning the WithEvents field to a new object automatically re-subscribes the handler to the new instance and unsubscribes from the old one.

🏏

Cricket analogy: A WithEvents field automatically re-subscribing when reassigned is like a team's designated wicketkeeper role transferring cleanly to a new player the moment the starting XI changes, without needing to manually reassign gloves.

For controls or objects not declared with WithEvents — such as ones created dynamically at runtime — use AddHandler someObject.SomeEvent, AddressOf Me.HandlerMethod to subscribe, and RemoveHandler someObject.SomeEvent, AddressOf Me.HandlerMethod to unsubscribe explicitly. This dynamic approach is the only option when you don't know at compile time which instance you'll be subscribing to.

Multicast Delegates and the EventHandler Pattern

Delegates in .NET are multicast: a single delegate instance internally maintains an invocation list, so multiple methods can be combined onto one delegate variable with the += operator (or AddHandler), and invoking the delegate calls each method in the list in order. The .NET Framework convention — followed idiomatically in VB.NET — is to declare events using the standard EventHandler or EventHandler(Of TEventArgs) delegate type, with a signature of (sender As Object, e As EventArgs), so that event consumers across any .NET class can rely on a consistent, predictable pattern rather than each class inventing its own custom delegate shape.

🏏

Cricket analogy: A multicast delegate invoking every subscriber in order is like a team huddle where the captain's instruction gets relayed down a fixed chain — bowler, then keeper, then slip cordon — each reacting in sequence.

If you subscribe to an event with AddHandler (or WithEvents) but never unsubscribe with RemoveHandler when the subscriber object is no longer needed, the publisher's invocation list keeps a live reference to the subscriber. This prevents the garbage collector from reclaiming the subscriber's memory — a classic .NET memory leak pattern, especially dangerous in long-lived publishers like a singleton service subscribed to by short-lived forms.

Lambda Expressions as Delegates

Since VB.NET added lambda expression support, you can assign an inline Function or Sub lambda directly to a delegate-typed variable or parameter without declaring a separate named method — for instance, AddHandler btn.Click, Sub(s, e) MessageBox.Show('Clicked') attaches an anonymous handler on the spot. This is convenient for short, one-off handlers, though for handlers you'll need to remove later with RemoveHandler, you must keep a reference to the exact same delegate instance, since a newly written identical-looking lambda is a different object and won't match for removal.

🏏

Cricket analogy: An inline lambda handler is like a substitute fielder called up for just one over rather than signed to the squad for the whole tournament — quick, situational, and not meant to be a permanent named player.

  • A delegate is a type-safe reference to a method, declared with Delegate and assigned via AddressOf.
  • Event declares a publisher-controlled notification member; only the owning class can call RaiseEvent to fire it.
  • WithEvents plus the Handles clause statically wires event handlers at compile time and re-subscribes automatically on reassignment.
  • AddHandler/RemoveHandler subscribe and unsubscribe dynamically, required for runtime-created objects or controls.
  • Delegates are multicast — combining handlers with += builds an invocation list called in order when the event fires.
  • The standard EventHandler(sender, e) signature is the idiomatic .NET pattern for consistent event consumption.
  • Forgetting RemoveHandler on long-lived publishers causes memory leaks by keeping subscribers alive via the invocation list.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#VBNETStudyNotes#EventsAndDelegatesInVBNET#Events#Delegates#NET#Defining#StudyNotes#SkillVeris#ExamPrep