Events and Delegates
22.1 Delegates
Public Delegate Function MathOperation(a As Integer, b As Integer) As Integer
Function Add(a As Integer, b As Integer) As Integer
Return a + b
End Function
Dim op As MathOperation = AddressOf Add
Console.WriteLine(op(3, 4)) ' 7
Dim op2 As MathOperation = Function(a, b) a * b
Console.WriteLine(op2.Invoke(3, 4)) ' 12
' Built-in generic delegates
Dim square As Func(Of Integer, Integer) = Function(x) x * x
Dim log As Action(Of String) = Sub(msg) Console.WriteLine(msg)
Dim isEven As Predicate(Of Integer) = Function(n) n Mod 2 = 0
Dim compare As Comparison(Of String) = Function(a, b) a.Length.CompareTo(b.Length)
' Multicast delegates
Dim notify As Action(Of String) = Sub(m) Console.WriteLine("Email: " & m)
notify = CType([Delegate].Combine(notify, New Action(Of String)(Sub(m) Console.WriteLine("SMS: " & m))), Action(Of String))
notify("Order shipped")22.2 Declaring and Raising Events
Public Class TemperatureSensor
Public Event TemperatureChanged(sender As Object, e As TemperatureEventArgs) ' event declaration
Public Event Alarm As EventHandler ' standard EventHandler
Private _temp As Double
Public Property Temperature As Double
Get
Return _temp
End Get
Set(value As Double)
If value <> _temp Then
_temp = value
RaiseEvent TemperatureChanged(Me, New TemperatureEventArgs(value))
If value > 100 Then RaiseEvent Alarm(Me, EventArgs.Empty)
End If
End Set
End Property
End Class
Public Class TemperatureEventArgs
Inherits EventArgs
Public ReadOnly Property Value As Double
Public Sub New(value As Double)
Me.Value = value
End Sub
End Class22.3 Handling Events: WithEvents/Handles (VB Style)
Handles wires handlers declaratively. That's how WinForms connects Button1.Click handlers.
One handler can handle multiple events: Handles btnOk.Click, btnCancel.Click.
Public Class Monitor
Private WithEvents _sensor As New TemperatureSensor()
Private Sub OnTempChanged(sender As Object, e As TemperatureEventArgs) Handles _sensor.TemperatureChanged
Console.WriteLine($"New temperature: {e.Value}")
End Sub
Private Sub OnAlarm(sender As Object, e As EventArgs) Handles _sensor.Alarm
Console.WriteLine("ALARM!")
End Sub
Public Sub Run()
_sensor.Temperature = 25
_sensor.Temperature = 105
End Sub
End Class22.4 Handling Events Dynamically: AddHandler/RemoveHandler
Dim sensor As New TemperatureSensor()
AddHandler sensor.TemperatureChanged, AddressOf ShowTemp
AddHandler sensor.Alarm, Sub(s, e) Console.WriteLine("Lambda alarm handler")
sensor.Temperature = 50
RemoveHandler sensor.TemperatureChanged, AddressOf ShowTemp ' prevents memory leaks22.5 Custom Events (Advanced)
Private _handlers As New List(Of EventHandler)
Public Custom Event DataReady As EventHandler
AddHandler(value As EventHandler)
_handlers.Add(value)
End AddHandler
RemoveHandler(value As EventHandler)
_handlers.Remove(value)
End RemoveHandler
RaiseEvent(sender As Object, e As EventArgs)
For Each h In _handlers
h.Invoke(sender, e)
Next
End RaiseEvent
End Event22.6 INotifyPropertyChanged (Data Binding)
Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Public Class ViewModelBase
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Function SetProperty(Of T)(ByRef field As T, value As T, <CallerMemberName> Optional name As String = Nothing) As Boolean
If EqualityComparer(Of T).Default.Equals(field, value) Then Return False
field = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
Return True
End Function
End Class