In Xojo, there are different ways to control the behavior of methods, events, and callbacks. Two commonly used mechanisms are AddHandler and Delegates. Both are designed to dynamically reference and invoke functions or methods at runtime. Although they share similar goals, they differ in implementation and usage. In this article, we will explain the similarities and differences between AddHandler and Delegates in Xojo and demonstrate how you can achieve the same result using both approaches.
What are Delegates?
A Delegate in Xojo is essentially a “pointer” to a method. It allows you to dynamically reference a method, treating it as if it were a variable. This means that a method can be passed to another method or function like a data variable.
' Defining a Delegate
Delegate Sub MyDelegateMethod(value As Integer)
' Method to be called
Sub PrintNumber(value As Integer)
MessageBox("Number: " + value.ToString)
End Sub
' Using the Delegate
Sub UseDelegate()
Var d As MyDelegateMethod = AddressOf PrintNumber
d.Invoke(10) ' Calls PrintNumber with the value 10
End Sub
In this example, a delegate MyDelegateMethod is defined to reference a method with an Integer parameter. Then, the method PrintNumber is assigned to the delegate variable d, and it is invoked using d.Invoke().
What is AddHandler?
The AddHandler command is used in Xojo to dynamically associate a method with an event. Instead of assigning an event handler in the design phase, this can be done at runtime. This allows for more flexible programming, especially in situations where event handling routines need to be assigned or changed dynamically.
' Method that acts as an event handler
Sub ButtonPressed(sender As DesktopButton)
MessageBox("Button was pressed!")
End Sub
' Using AddHandler
Sub SetupButtonHandler(button As DesktopButton)
AddHandler button.Pressed, AddressOf ButtonPressed
End Sub
In this example, the ButtonPressed method is dynamically associated with the Pressed event of a DesktopButton. When the button is pressed, the ButtonPressed method shows a message.
Important Note: Using RemoveHandler with AddHandler
Whenever you use AddHandler, it’s important to remember to use RemoveHandler to properly un-assign the event handler when it’s no longer needed. If you fail to remove the handler, you may encounter memory leaks or unexpected behavior, especially when working with objects that are frequently created and destroyed.
' Removing the event handler
Sub RemoveButtonHandler(button As DesktopButton)
RemoveHandler button.Pressed, AddressOf ButtonPressed
End Sub
In this case, RemoveHandler is used to detach the ButtonPressed method from the Pressed event of the DesktopButton. This is especially useful when a button or event source is about to be destroyed or when you no longer want the handler to respond to events.
Similarities between AddHandler and Delegates
- Dynamic Behavior: Both Delegates and AddHandler allow for the dynamic assignment of methods, providing more flexibility in the flow of the program.
- Method Referencing: Both concepts use the AddressOf syntax to reference a method.
- Flexibility: Both mechanisms are useful for reacting to specific events or functions at runtime.
Differences between AddHandler and Delegates
1. Purpose:
- Delegates are more general and are used to treat methods as variables and pass them as parameters to other methods.
- AddHandler is specifically designed for event handling. It is used to assign methods to events at runtime.
2. Target Structure:
- Delegates are strongly typed. They require an exact match between the method signature and the delegate.
- AddHandler binds methods to events, which require a predetermined signature but are dictated by the context of the object used.
3. Lifetime:
- Delegates can exist as standalone variables within any scope.
- AddHandler is tied to the event and object it is associated with. If the event or object is destroyed, the handler is no longer called.
Achieving the same functionality with both approaches
Event Handling with AddHandler
Let’s assume we have a timer event and want to specify at runtime which method should be called when the timer elapses.
' Method called by the Timer event
Sub TimerAction(sender As Timer)
MessageBox("Timer elapsed!")
End Sub
' Dynamically assigning the event with AddHandler
Sub SetupTimer(timer As Timer)
#If TargetMobile
AddHandler timer.Run, AddressOf TimerAction
#Else
AddHandler timer.Action, AddressOf TimerAction
#EndIf
timer.RunMode = Timer.RunModes.Multiple
timer.Period = 1000
End Sub
In this example, the TimerAction method is assigned to the Run/Action event of a timer at runtime.
Same Functionality with Delegates
Now, the same logic but using Delegates:
' Defining a Delegate for Timer actions
Delegate Sub TimerDelegate(sender As Timer)
' Method to be called
Sub TimerAction(sender As Timer)
MessageBox("Timer elapsed!")
End Sub
' Assigning and invoking the method via a Delegate
Sub SetupTimerWithDelegate(timer As Timer)
Var d As TimerDelegate = AddressOf TimerAction
#If TargetMobile
AddHandler timer.Run, d
#Else
AddHandler timer.Action, d
#EndIf
timer.RunMode = Timer.RunModes.Multiple
timer.Period = 1000
End Sub
In this case, a Delegate is used to reference the same TimerAction method, but the structure remains nearly identical.
AddHandler and Delegates both provide ways to dynamically handle methods at runtime in Xojo. While Delegates are more flexible and general-purpose, AddHandler is specifically designed for dynamic event handling. Both mechanisms are useful depending on the use case. The main difference lies in how they are used and their target structure: Delegates are strongly typed and can be used anywhere in the code, whereas AddHandler is used to link methods to events dynamically.
Additionally, when using AddHandler, it is crucial to remember to use RemoveHandler to properly unbind event handlers when they are no longer needed. Failing to do so can lead to performance issues, memory leaks, or unintended behavior, especially when dealing with dynamic or temporary objects.
By combining these two techniques, you can make Xojo programs more flexible and dynamic.
Happy Coding!
Martin T. is a Xojo MVP and has been very involved in testing Android support.