Compartir a través de


Control y generación de eventos

Los eventos de .NET se basan en el modelo de delegado. El modelo de delegado sigue el patrón de diseño de observador, que permite a un suscriptor registrarse y recibir notificaciones de un proveedor. Un remitente de eventos inserta una notificación cuando se produce un evento. Un receptor de eventos define la respuesta. En este artículo se describen los componentes principales del modelo de delegado, cómo consumir eventos en las aplicaciones y cómo implementar eventos en el código.

Generar eventos con un emisor de eventos

Un evento es un mensaje enviado por un objeto para indicar la aparición de una acción. La acción puede ser la interacción del usuario, como una pulsación de botón, o puede resultar de otra lógica de programa, como un cambio de valor de propiedad. El objeto que genera el evento se denomina remitente del evento. El remitente del evento no conoce el objeto o método que recibe (controla) los eventos que genera. El evento normalmente es un miembro del emisor del evento. Por ejemplo, el Click evento es miembro de la Button clase y el PropertyChanged evento es miembro de la clase que implementa la INotifyPropertyChanged interfaz .

Para definir un evento, use el evento de C# o la palabra clave Event de Visual Basic en la firma de la clase de eventos y especifique el tipo de delegado para el evento. Los delegados se describen en la sección siguiente.

Normalmente, para generar un evento, se agrega un método marcado como protected y virtual (en C#) o Protected ( Overridable en Visual Basic). La convención de nomenclatura del método es On<EventName>, como OnDataReceived. El método debe tomar un parámetro que especifique un objeto de datos de evento, que es un objeto de tipo EventArgs o un tipo derivado. Proporcione este método para permitir que las clases derivadas invaliden la lógica para generar el evento. Una clase derivada siempre debe llamar al On<EventName> método de la clase base para asegurarse de que los delegados registrados reciban el evento.

En el ejemplo siguiente se muestra cómo declarar un evento denominado ThresholdReached. El evento está asociado al EventHandler delegado y se genera en un método denominado OnThresholdReached:

class Counter
{
    public event EventHandler ThresholdReached;

    protected virtual void OnThresholdReached(EventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }

    // provide remaining implementation for the class
}
Public Class Counter
    Public Event ThresholdReached As EventHandler

    Protected Overridable Sub OnThresholdReached(e As EventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub

    ' provide remaining implementation for the class
End Class

Declarar firmas de delegados para controladores de eventos

Un delegado es un tipo que tiene una referencia a un método. Un delegado se declara con una firma que muestra el tipo de valor devuelto y los parámetros para los métodos a los que hace referencia. Solo puede contener referencias a métodos que coincidan con su firma. Un delegado equivale a un puntero a función con seguridad o a una devolución de llamada. Una declaración de delegado es suficiente para definir una clase de delegado.

Los delegados tienen muchos usos en .NET. En el contexto de los eventos, un delegado es un intermediario (o mecanismo similar al puntero) entre el origen del evento y el código que controla el evento. Para asociar un delegado a un evento, incluya el tipo delegado en la declaración de evento, como se muestra en el ejemplo de la sección anterior. Para obtener más información sobre los delegados, consulte la Delegate clase .

.NET proporciona los delegados EventHandler y EventHandler<TEventArgs> que admiten la mayoría de los escenarios de eventos. Use el delegado EventHandler en todos los eventos que no incluyan datos de evento. Use el delegado EventHandler<TEventArgs> para los eventos que incluyen datos sobre el evento. Estos delegados no tienen ningún valor de tipo devuelto y toman dos parámetros (un objeto para el origen del evento y un objeto para los datos del evento).

Los delegados son objetos de clase de multidifusión, lo que significa que pueden guardar referencias a más de un método de control de eventos. Para obtener más información, consulte la Delegate página de referencia. Los delegados proporcionan flexibilidad y control específico en el control de eventos. Un delegado actúa como remitente de eventos de la clase que genera el evento y mantiene una lista de los controladores registrados para el evento.

Use los EventHandler tipos de delegado y EventHandler<TEventArgs> para definir el delegado necesario. Marca un delegado con el delegate tipo en C# o el Delegate tipo de Visual Basic en la declaración. En el ejemplo siguiente se muestra cómo declarar un delegado denominado ThresholdReachedEventHandler:

public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
Public Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)

Trabajar con clases de datos de eventos

Los datos asociados a un evento se pueden proporcionar a través de una clase de datos de eventos. .NET proporciona muchas clases de datos de eventos que puede usar en las aplicaciones. Por ejemplo, la SerialDataReceivedEventArgs clase es la clase de datos de eventos para el SerialPort.DataReceived evento. .NET sigue un patrón de nomenclatura donde todas las clases de datos de eventos terminan con el EventArgs sufijo. Para determinar qué clase de datos de evento está asociada a un evento, basta con examinar el delegado del evento. Por ejemplo, el SerialDataReceivedEventHandler delegado incluye la SerialDataReceivedEventArgs clase como parámetro.

Normalmente, la EventArgs clase es el tipo base para las clases de datos de eventos. También se usa esta clase si un evento no tiene ningún dato asociado. Cuando se crea un evento que notifica a los suscriptores que algo ha ocurrido sin datos adicionales, incluya la EventArgs clase como el segundo parámetro del delegado. Puede pasar el EventArgs.Empty valor cuando no se proporciona ningún dato. El EventHandler delegado incluye la EventArgs clase como parámetro.

Puede crear una clase que derive de la EventArgs clase para proporcionar los miembros necesarios para pasar datos relacionados con el evento. Normalmente, debe usar el mismo patrón de nomenclatura que .NET y finalizar el nombre de la clase de datos de eventos con el EventArgs sufijo .

En el ejemplo siguiente se muestra una clase de datos de eventos denominada ThresholdReachedEventArgs que contiene propiedades específicas del evento que se está generando:

public class ThresholdReachedEventArgs : EventArgs
{
    public int Threshold { get; set; }
    public DateTime TimeReached { get; set; }
}
Public Class ThresholdReachedEventArgs
    Inherits EventArgs

    Public Property Threshold As Integer
    Public Property TimeReached As DateTime
End Class

Responder a eventos con controladores

Para responder a un evento, defina un método de controlador de eventos en el receptor de eventos. Este método debe coincidir con la signatura del delegado del evento que se está controlando. En el controlador de eventos, se realizan las acciones necesarias cuando se genera el evento, como recopilar la entrada del usuario después de que el usuario presione un botón. Para recibir notificaciones cuando se produce el evento, el método del controlador de eventos debe suscribirse al evento.

En el ejemplo siguiente se muestra un método de controlador de eventos denominado c_ThresholdReached que coincide con la firma del EventHandler delegado. El método se suscribe al ThresholdReached evento :

class ProgramTwo
{
    static void Main()
    {
        var c = new Counter();
        c.ThresholdReached += c_ThresholdReached;

        // provide remaining implementation for the class
    }

    static void c_ThresholdReached(object sender, EventArgs e)
    {
        Console.WriteLine("The threshold was reached.");
    }
}
Module Module1

    Sub Main()
        Dim c As New Counter()
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached

        ' provide remaining implementation for the class
    End Sub

    Sub c_ThresholdReached(sender As Object, e As EventArgs)
        Console.WriteLine("The threshold was reached.")
    End Sub
End Module

Uso de controladores de eventos estáticos y dinámicos

.NET permite a los suscriptores registrarse para las notificaciones de eventos de forma estática o dinámica. Los controladores de eventos estáticos son efectivos durante toda la vida de la clase cuyos eventos controlan. Los controladores de eventos dinámicos se activan y desactivan explícitamente durante la ejecución del programa, normalmente en respuesta a alguna lógica de programa condicional. Puede usar controladores dinámicos cuando solo se necesiten notificaciones de eventos en determinadas condiciones o cuando las condiciones en tiempo de ejecución determinen el controlador específico al que llamar. En el ejemplo de la sección anterior se muestra cómo agregar dinámicamente un controlador de eventos. Para obtener más información, vea Eventos (en Visual Basic) y Eventos (en C#).

Generación de varios eventos

Si la clase genera varios eventos, el compilador genera un campo por instancia de delegado de eventos. Si el número de eventos es grande, es posible que el costo de almacenamiento de un campo por cada delegado no sea aceptable. En estos escenarios, .NET proporciona propiedades de evento que puede usar con otra estructura de datos de su elección para almacenar delegados de eventos.

Las propiedades de evento están compuestas de declaraciones de evento acompañadas de descriptores de acceso de evento. Los accesores de eventos son métodos que se definen para agregar o quitar instancias de delegados de eventos de la estructura de almacenamiento.

Nota:

Las propiedades de evento son más lentas que los campos de evento, ya que se debe recuperar cada delegado de evento antes de poder invocarlo.

La memoria y la velocidad se ven afectadas. Si la clase define muchos eventos que se generan con poca frecuencia, debe implementar propiedades de evento. Para obtener más información, consulte Control de varios eventos mediante propiedades de eventos.

En los siguientes recursos se describen otras tareas y conceptos relacionados con el trabajo con eventos:

Revisión de la referencia de especificación

La documentación de referencia de especificación está disponible para las API que admiten el control de eventos:

Nombre de la API Tipo de API Referencia
EventHandler Delegar EventHandler
EventHandler<TEventArgs> Delegar EventHandler<TEventArgs>
EventArgs Clase EventArgs
Delegar Clase Delegate