Uso de AddHandler y Delegados en Xojo

A continuación encontrarás traducido al castellano el artículo escrito por Martin T. y publicado originalmente en el Blog oficial de Xojo.

Xojo proporciona varias formas a la hora de controlar el comportamiento de los métodos, eventos y callbacks. Dos de los mecanismos más frecuentemente utilizados son AddHandler y los delegados (Delegates). Ambos están diseñados para hacer referencia y ejecutar, de forma dinámica, tanto funciones como métodos en tiempo de ejecución. Si bien comparten objetivos similares, estos difieren tanto en la implementación como en su uso.

En este artículo explicaremos tanto las similitudes como las diferencias entre AddHandler y Delegate en Xojo, además de mostrar como puedes obtener los mismos resultados utilizando ambos enfoques.

¿Qué son los Delegados?

En Xojo, un Delegado es esencialmente un “apuntador” a un método. Este te permite referenciar de forma dinámica un método tratándolo como si fuese una variable. Esto significa que un método puede ser pasado a otro método o función como si de una variable se tratase.

' Definiendo un Delegado
Delegate Sub MyDelegateMethod(value As Integer)
 
' Método que se llamará
Sub PrintNumber(value As Integer)
  MessageBox("Number: " + value.ToString)
End Sub
 
' Usando el Delegado
Sub UseDelegate()
  Var d As MyDelegateMethod = AddressOf PrintNumber
  d.Invoke(10) ' Llama a PrintNumber con el valor 10
End Sub

En este ejemplo el delegado MyDelegateMethod está definido para referenciar a un método con un parámetro de tipo entero. Luego, el método PintNumber se asigna a la variable de delegado con el nombre “d”, y se invoca utilizando d.Invoke().

¿Qué es AddHandler?

El comando AddHandler se utiliza en Xojo para asociar de forma dinámica un método con un evento. En vez de asignar un manejador de evento en la fase de diseño, esto puede realizarse en tiempo de ejecución. Esto permite realizar una programación más flexible, especialmente en situaciones donde las rutinas de gestión de eventos necesitan ser asignadas o cambiadas de forma dinámica.

' Método que actúa como manejador de evento
Sub ButtonPressed(sender As DesktopButton)
  MessageBox("Button was pressed!")
End Sub
 
' Usando AddHandler
Sub SetupButtonHandler(button As DesktopButton)
  AddHandler button.Pressed, AddressOf ButtonPressed
End Sub

En este ejemplo, el método ButtonPressed es asociado de forma dinámica con el evento Pressed de un DesktopButton. Cuando se pulse sobre el botón, el método ButtonPressed será el encargado de mostrar un mensaje.

Uso de RemoveHandler con AddHandler

Cuando utilices AddHandler es importante recordar que ha de utilizarse RemoveHandler para eliminar la asignación del manejador de evento cuando ya no se utilice. Si no se elimina el handler te encontrarás con fugas de memoria o bien un comportamiento errático, especialmente cuando estés trabajando con objetos que se crean y destruyen con frecuencia.

' Eliminando la asignación del manejador de evento
Sub RemoveButtonHandler(button As DesktopButton)
  RemoveHandler button.Pressed, AddressOf ButtonPressed
End Sub

En este caso, se utiliza RemoveHandler para desasociar el método ButtonPressed del evento Pressed correspondiente a un DesktopButton. Esto es especialmente útil cuando un botón o fuente de evento está a punto de ser destruido, o bien cuando ya no desees que el manejador responda a los eventos.

Similitudes entre AddHandler y los Delegados

  • Comportamiento dinámico: Tanto los Delegados como AddHandler permiten la asignación dinámica de métodos, resultando en un flujo más flexible del programa.
  • Referencia a métodos: ambos conceptos utilizan la sintaxis AddressOf para referenciar un método.
  • Flexibilidad: ambos mecanismos son útiles para reaccionar a eventos o funciones específicas en tiempo de ejecución.

Diferencias entre AddHandler y Delegados

1. Propósito:

Los Delegados son más generales y se utilizan para tratar a los métodos como variables y pasarlos como parámetros a otros métodos.

AddHandler está diseñado especialmente para la gestión de eventos. Se utiliza para asignar métodos a eventos en tiempo de ejecución.

2. Estructura destino:

Los Delegados son de tipado fuerte. Se requiere de una correspondencia exacta entre la signatura del método y el delegado.

AddHandler enlaza los métodos a eventos, lo que requiere de una signatura predeterminada pero está dictada por el contexto del objeto a utilizar.

3. Ciclo de vida:

Los Delegados pueden existir como variables independientes en cualquier ámbito.

AddHandler está sujeto al evento y objeto con el que está asociado. Si el evento o el objeto se destruye, ya no se podrá llamar al manejador.

Obtener la misma funcionalidad con ambos enfoques

Gestion de Eventos con AddHandler

Pongamos por caso que tenemos un evento timer y queremos indicar en tiempo de ejecución cual será el método a llamar cuando finalice el tiempo.

' Método llamado por el evento del Timer
Sub TimerAction(sender As Timer)
  MessageBox("Timer elapsed!")
End Sub
 
' Asignando de forma dinámica a un evento con 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

En este ejemplo, el método TimerAction se asigna al evento Run/Action del Timer en tiempo de ejecución.

Misma funcionalidad con Delegados

Veamos ahora la misma lógica pero usando Delegados:

' Definimos un Delegado para las acciones de Timer
Delegate Sub TimerDelegate(sender As Timer)
 
' Método que se invocará
Sub TimerAction(sender As Timer)
  MessageBox("Timer elapsed!")
End Sub
 
' Asignando e invocando el método mediante Delegado
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

En este caso se utiliza un Delegado para referencia al mismo método TimerAction, pero la estructura permanece casi idéntica.

AddHandler y los Delegados proporcionan modos de gestionar métodos de forma dinámica en tiempo de ejecución con Xojo. Si bien los Delegados son más flexibles y de propósito general, AddHandler está diseñado específicamente para la gestión dinámica de eventos.

Ambos mecanismos son útiles en función del caso de uso. La principal diferencia reside en cómo se utilizan y su estructura final: los delegados son de tipado fuerte y pueden utilizarse en cualquier parte del código, mientras que AddHandler se utiliza para enlazar métodos de forma dinámica con los eventos.

Adicionalmente, cuando se utiliza AddHandler es crucial acordarse de utilizar RemoveHandler para romper adecuadamente el vínculo entre el método y el evento gestionado cuando ya no sea necesario. Si no se hace, puede derivar en problemas de rendimiento, fugas de memoria o bien un comportamiento no deseado.

Al combinar estas dos técnicas lograrás que tus programas Xojo sean más flexibles y dinámicos.

¡Feliz programación!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *