Definición y manejo de eventos en Visual Basic .NET (VB.NET)
En VB.NET (y .NET en general), un evento es un mecanismo de notificación: un objeto (publicador) avisa a otros objetos (suscriptores) de que "algo ha ocurrido" (clic, tecla, timer, dato cambiado, error, finalización async). Permite programación reactiva y desacoplada.
Conceptos clave
- Publicador (Publisher): Clase que expone el evento (ej.
Button,Timer, tu claseFactura). - Suscriptor (Subscriber): Clase que maneja el evento (ej. Formulario, Controlador, Servicio).
- Delegado (Delegate): Tipo que define la firma del manejador (parámetros y tipo retorno). .NET usa
EventHandler(sender, e) oEventHandler(Of TEventArgs). - Argumentos del evento (EventArgs): Clase que transporta datos del evento. Hereda de
EventArgs. Ej:MouseEventArgs(X, Y, Button),ElapsedEventArgs(SignalTime). - Manejador (Handler): Sub/Function con firma compatible al delegado. Ejecuta la lógica de respuesta.
- Suscripción (Wire-up): Conectar evento con manejador:
AddHandler obj.Evento, AddressOf MiManejador(dinámico) oHandles obj.Evento(estático, en tiempo diseño, WithEvents). - Desuscripción:
RemoveHandler obj.Evento, AddressOf MiManejador. Vital para evitar memory leaks (referencias fuertes impiden GC).
Eventos predefinidos comunes (WinForms / WPF / ASP.NET)
- UI: Click, DoubleClick, MouseDown/Up/Move/Enter/Leave/Hover/Wheel, KeyDown/Up/Press, TextChanged, Validating/Validated, GotFocus/LostFocus, Load/Shown/Closing/FormClosing, Paint/DrawItem.
- Componentes: Timer.Tick, SerialPort.DataReceived, FileSystemWatcher.Created/Changed/Deleted/Renamed, BackgroundWorker.DoWork/ProgressChanged/RunWorkerCompleted, HttpClient (async events), Socket.Received.
- Datos: BindingSource.CurrentChanged, DataTable.RowChanged/RowDeleting/ColumnChanging, EntityFramework SavedChanges.
Declarar evento personalizado (En tu clase)
Public Class Factura
' 1. Definir EventArgs personalizado (opcional pero recomendado)
Public Class FacturaEventArgs
Inherits EventArgs
Public Property FacturaId As Integer
Public Property Total As Decimal
Public Property Fecha As DateTime
Public Sub New(id As Integer, total As Decimal, fecha As DateTime)
Me.FacturaId = id : Me.Total = total : Me.Fecha = fecha
End Sub
End Class
' 2. Declarar el evento (usa EventHandler(Of T) estándar)
Public Event FacturaCreada As EventHandler(Of FacturaEventArgs)
' 3. Método protegido para lanzar (Raise) el evento (patrón estándar)
Protected Overridable Sub OnFacturaCreada(e As FacturaEventArgs)
RaiseEvent FacturaCreada(Me, e) ' Notifica a suscriptores
End Sub
' 4. Lógica de negocio que dispara el evento
Public Sub CrearNueva(clienteId As Integer, items As List(Of Item))
' ... lógica crear factura, calcular total ...
Dim nuevaFacturaId = 123
Dim total = 99.99D
' 5. LANZAR (RAISE) EL EVENTO
OnFacturaCreada(New FacturaEventArgs(nuevaFacturaId, total, DateTime.Now))
End Sub
End Class
Suscribirse al evento (En Form, Servicio, etc.)
Public Class FacturaForm
Private WithEvents miFactura As New Factura() ' WithEvents permite Handles
' Suscripción ESTÁTICA (En tiempo diseño, requiere WithEvents)
Private Sub miFactura_FacturaCreada(sender As Object, e As Factura.FacturaEventArgs) Handles miFactura.FacturaCreada
MessageBox.Show($"Factura {e.FacturaId} creada: {e.Total:C} el {e.Fecha:G}")
ActualizarGrid()
EnviarEmailCliente(e.FacturaId)
End Sub
' Suscripción DINÁMICA (En tiempo ejecución, SIN WithEvents)
Private Sub SuscribirOtraFactura(f As Factura)
AddHandler f.FacturaCreada, AddressOf ManejadorGenericoFactura
End Sub
Private Sub ManejadorGenericoFactura(sender As Object, e As Factura.FacturaEventArgs)
Log.Info($"Factura {e.FacturaId} total {e.Total}")
End Sub
' LIMPIEZA: Desuscribir al cerrar/destruir
Private Sub FacturaForm_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
RemoveHandler miFactura.FacturaCreada, AddressOf miFactura_FacturaCreada
' Si suscripciones dinámicas, guárdalas en lista y RemoveHandler todas aquí.
End Sub
End Class
Patrón Event-Based Asynchronous (EAP) / Task-based (TAP) moderno
Para operaciones largas, usa Async/Await + Task en lugar de eventos BackgroundWorker (legacy). Los eventos siguen útiles para progreso (IProgress(Of T)), notificaciones de estado, UI, dominio (Domain Events).
Buenas prácticas
- Nombra eventos en pasado (
FacturaCreada,UsuarioIniciadoSesion,ArchivoProcesado). - Usa
EventHandler(Of TEventArgs)estándar. Evita delegados custom. sender= instancia que lanza (Me).e= datos.- Thread Safety: Si evento se lanza desde hilo distinto al UI, usa
Invoke / BeginInvoke(WinForms) /Dispatcher.Invoke(WPF) /SynchronizationContexten manejador para tocar UI. - Memory Leaks: SIEMPRE
RemoveHandler/-=enDispose,FormClosing,Unloaded.WeakEventManager(WPF) /WeakReferencepara suscripciones longevas. - Documenta
EventArgscon XML comments (''').
- ·¿Se pueden crear apps para Android con Visual Basic?
- ·¿Puedo crear apps para Android con Visual Basic?
- ·Definición de equipo audiovisual
- ·Definición básica de TV por cable
- ·Definición de chat en Internet: tipos, beneficios y riesgos
- ·Definición de dispositivos de comunicación
- ·Definición de etiquetas de datos
- ·Cómo programar ecuaciones cuadráticas en Visual Basic
