Controlar y provocar eventosHandling and Raising Events

Los eventos de .NET Framework se basan en un modelo de delegado.Events in the .NET Framework are based on the delegate model. El modelo de delegado sigue el patrón de diseño del observador, que permite que un suscriptor se registre con un proveedor y reciba notificaciones de dicho proveedor.The delegate model follows the observer design pattern, which enables a subscriber to register with, and receive notifications from, a provider. El emisor de un evento inserta una notificación de que se ha producido un evento, y un receptor de eventos recibe la notificación y define una respuesta a la misma.An event sender pushes a notification that an event has happened, and an event receiver receives that notification and defines a response to it. 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.This article describes the major components of the delegate model, how to consume events in applications, and how to implement events in your code.

Para información sobre el control de eventos en las aplicaciones de la Tienda Windows 8.xWindows 8.x Store, vea Introducción a eventos y eventos enrutados (aplicaciones de la Tienda Windows).For information about handling events in Tienda Windows 8.xWindows 8.x Store apps, see Events and routed events overview (Windows store apps).

EventosEvents

Un evento es un mensaje que envía un objeto cuando ocurre una acción.An event is a message sent by an object to signal the occurrence of an action. La acción podría ser debida a la interacción del usuario, como hacer clic en un botón, o podría proceder de cualquier otra lógica del programa, como el cambio del valor de una propiedad.The action could be caused by user interaction, such as a button click, or it could be raised by some other program logic, such as changing a property’s value. El objeto que provoca el evento se conoce como emisor del evento.The object that raises the event is called the event sender. El emisor del evento no sabe qué objeto o método recibirá (controlará) los eventos que genera.The event sender doesn't know which object or method will receive (handle) the events it raises. El evento normalmente es un miembro del emisor del evento; por ejemplo, el evento Click es un miembro de la clase Button, y el evento PropertyChanged es un miembro de la clase que implementa la interfaz INotifyPropertyChanged.The event is typically a member of the event sender; for example, the Click event is a member of the Button class, and the PropertyChanged event is a member of the class that implements the INotifyPropertyChanged interface.

Para definir un evento, se utiliza la palabra clave event (en C#) o Event (en Visual Basic) en la signatura de la clase de eventos y se especifica el tipo de delegado para el evento.To define an event, you use the event (in C#) or Event (in Visual Basic) keyword in the signature of your event class, and specify the type of delegate for the event. Los delegados se describen en la sección siguiente.Delegates are described in the next section.

Normalmente, para generar un evento, se agrega un método marcado como protected y virtual (en C#) o Protected y Overridable (en Visual Basic).Typically, to raise an event, you add a method that is marked as protected and virtual (in C#) or Protected and Overridable (in Visual Basic). Asigne a este método el nombre OnEventName; por ejemplo, OnDataReceived.Name this method OnEventName; for example, OnDataReceived. El método debe tomar un parámetro que especifica un objeto de datos de evento.The method should take one parameter that specifies an event data object. Este método se proporciona para permitir que las clases derivadas reemplacen la lógica para generar el evento.You provide this method to enable derived classes to override the logic for raising the event. Una clase derivada siempre debería llamar al método OnEventName de la clase base para asegurarse de que los delegados registrados reciben el evento.A derived class should always call the OnEventName method of the base class to ensure that registered delegates receive the event.

En el ejemplo siguiente se muestra cómo declarar un evento denominado ThresholdReached.The following example shows how to declare an event named ThresholdReached. El evento está asociado al delegado EventHandler y se genera en un método denominado OnThresholdReached.The event is associated with the EventHandler delegate and raised in a method named OnThresholdReached.

class Counter
{
    public event EventHandler ThresholdReached;

    protected virtual void OnThresholdReached(EventArgs e)
    {
        EventHandler handler = ThresholdReached;
        if (handler != null)
        {
            handler(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

DelegadosDelegates

Un delegado es un tipo que tiene una referencia a un método.A delegate is a type that holds a reference to a method. Los delegados se declaran con una signatura que muestra el tipo de valor devuelto y los parámetros para los métodos a los que hacen referencia, y únicamente pueden contener referencias a los métodos que coinciden con su signatura.A delegate is declared with a signature that shows the return type and parameters for the methods it references, and can hold references only to methods that match its signature. Por lo tanto, un delegado equivale a un puntero a función con seguridad o a una devolución de llamada.A delegate is thus equivalent to a type-safe function pointer or a callback. Una declaración de delegado es suficiente para definir una clase de delegado.A delegate declaration is sufficient to define a delegate class.

Los delegados tienen muchos usos en .NET Framework.Delegates have many uses in the .NET Framework. En el contexto de los eventos, un delegado es un intermediario (o un mecanismo de puntero) entre el origen del evento y el código que lo controla.In the context of events, a delegate is an intermediary (or pointer-like mechanism) between the event source and the code that handles the event. Para asociar un delegado a un evento se incluye el tipo de delegado en la declaración del evento, como se muestra en el ejemplo de la sección anterior.You associate a delegate with an event by including the delegate type in the event declaration, as shown in the example in the previous section. Para obtener más información sobre los delegados, vea la clase Delegate.For more information about delegates, see the Delegate class.

.NET Framework proporciona los delegados EventHandler y EventHandler<TEventArgs> que admiten la mayoría de los escenarios de eventos.The .NET Framework provides the EventHandler and EventHandler<TEventArgs> delegates to support most event scenarios. Use el delegado EventHandler para todos los eventos que no incluyen datos de evento.Use the EventHandler delegate for all events that do not include event data. Use el delegado EventHandler<TEventArgs> para los eventos que incluyen datos sobre el evento.Use the EventHandler<TEventArgs> delegate for events that include data about the event. 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).These delegates have no return type value and take two parameters (an object for the source of the event and an object for event data).

Los delegados son de multidifusión, lo que significa que pueden guardar referencias a más de un método de control de eventos.Delegates are multicast, which means that they can hold references to more than one event-handling method. Para obtener información detallada, vea la página de referencia de Delegate.For details, see the Delegate reference page. Los delegados permiten realizar un control de eventos más flexible y detallado.Delegates provide flexibility and fine-grained control in event handling. 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.A delegate acts as an event dispatcher for the class that raises the event by maintaining a list of registered event handlers for the event.

Para los escenarios en que no funcionan los delegados EventHandler y EventHandler<TEventArgs>, puede definir un delegado.For scenarios where the EventHandler and EventHandler<TEventArgs> delegates do not work, you can define a delegate. Los escenarios para los es necesario definir un delegado son poco habituales, como cuando se debe ejecutar código que no reconoce genéricos.Scenarios that require you to define a delegate are very rare, such as when you must work with code that does not recognize generics. Los delegados se marcan con la palabra clave delegate en (C#) y Delegate (en Visual Basic) en la declaración.You mark a delegate with the delegate in (C#) and Delegate (in Visual Basic) keyword in the declaration. En el ejemplo siguiente se muestra cómo declarar un delegado denominado ThresholdReachedEventHandler.The following example shows how to declare a delegate named ThresholdReachedEventHandler.

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

Datos de eventoEvent Data

Los datos asociados a un evento se pueden proporcionar a través de una clase de datos de evento.Data that is associated with an event can be provided through an event data class. .NET Framework proporciona muchas clases de datos de evento que puede utilizar en las aplicaciones.The .NET Framework provides many event data classes that you can use in your applications. Por ejemplo, la clase SerialDataReceivedEventArgs es la clase de datos de evento del evento SerialPort.DataReceived.For example, the SerialDataReceivedEventArgs class is the event data class for the SerialPort.DataReceived event. En .NET Framework se sigue un patrón de nombres que consiste en finalizar todas las clases de datos de evento con EventArgs.The .NET Framework follows a naming pattern of ending all event data classes with EventArgs. Para determinar qué clase de datos de evento está asociada a un evento, basta con examinar el delegado del evento.You determine which event data class is associated with an event by looking at the delegate for the event. Por ejemplo, el delegado SerialDataReceivedEventHandler incluye entre sus parámetros la clase SerialDataReceivedEventArgs.For example, the SerialDataReceivedEventHandler delegate includes the SerialDataReceivedEventArgs class as one of its parameters.

La clase EventArgs es el tipo base para todas las clases de datos de evento.The EventArgs class is the base type for all event data classes. EventArgs también es la clase que se usa cuando un evento no tiene datos asociados.EventArgs is also the class you use when an event does not have any data associated with it. Cuando cree un evento que solo sirva para notificar a otras clases que algo ha sucedido y que no necesite pasar ningún dato, incluya la clase EventArgs como segundo parámetro del delegado.When you create an event that is only meant to notify other classes that something happened and does not need to pass any data, include the EventArgs class as the second parameter in the delegate. Puede pasar el valor EventArgs.Empty cuando no se proporciona ningún dato.You can pass the EventArgs.Empty value when no data is provided. El delegado EventHandler incluye la clase EventArgs como parámetro.The EventHandler delegate includes the EventArgs class as a parameter.

Si desea crear una clase de datos de evento personalizada, cree una clase que se derive de EventArgs y, a continuación, especifique los miembros que sean necesarios para pasar los datos relacionados con el evento.When you want to create a customized event data class, create a class that derives from EventArgs, and then provide any members needed to pass data that is related to the event. Normalmente, debe usar el mismo patrón de asignación de nombres que se usa en .NET Framework y finalizar el nombre de la clase de los datos de evento con EventArgs.Typically, you should use the same naming pattern as the .NET Framework and end your event data class name with EventArgs.

En el ejemplo siguiente se muestra una clase de datos de evento denominada ThresholdReachedEventArgs.The following example shows an event data class named ThresholdReachedEventArgs. Contiene propiedades específicas del evento que se genera.It contains properties that are specific to the event being raised.

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

Controladores de eventosEvent Handlers

Para responder a un evento, se define un método controlador de eventos en el receptor de eventos.To respond to an event, you define an event handler method in the event receiver. Este método debe coincidir con la signatura del delegado del evento que se está controlando.This method must match the signature of the delegate for the event you are handling. En el controlador de eventos, se realizan las acciones que es necesario llevar a cabo cuando se genera el evento, como recopilar los datos proporcionados por el usuario cuando este hace clic en un botón.In the event handler, you perform the actions that are required when the event is raised, such as collecting user input after the user clicks a button. Para recibir notificaciones cuando se genera el evento, el método controlador de eventos debe suscribirse al evento.To receive notifications when the event occurs, your event handler method must subscribe to the event.

En el ejemplo siguiente se muestra un método de control de eventos denominado c_ThresholdReached que coincide con la signatura del delegado EventHandler.The following example shows an event handler method named c_ThresholdReached that matches the signature for the EventHandler delegate. El método se suscribe al evento ThresholdReached.The method subscribes to the ThresholdReached event.

class Program
{
    static void Main(string[] args)
    {
        Counter 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 Counter = 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

Controladores de eventos estáticos y dinámicosStatic and Dynamic Event Handlers

.NET Framework permite a los suscriptores registrarse para las notificaciones de eventos estática o dinámicamente.The .NET Framework allows subscribers to register for event notifications either statically or dynamically. Los controladores de eventos estáticos son efectivos durante toda la vida de la clase cuyos eventos controlan.Static event handlers are in effect for the entire life of the class whose events they handle. Los controladores de eventos dinámicos se activan y desactivan explícitamente durante la ejecución de un programa, normalmente en respuesta a alguna lógica condicional del programa.Dynamic event handlers are explicitly activated and deactivated during program execution, usually in response to some conditional program logic. Por ejemplo, pueden utilizarse si las notificaciones de eventos solo son necesarias en condiciones específicas o si una aplicación proporciona varios controladores de eventos y las condiciones en tiempo de ejecución determinan cuál es el que debe utilizarse.For example, they can be used if event notifications are needed only under certain conditions or if an application provides multiple event handlers and run-time conditions define the appropriate one to use. En el ejemplo de la sección anterior se muestra cómo agregar dinámicamente un controlador de eventos.The example in the previous section shows how to dynamically add an event handler. Para más información, consulte Eventos y Eventos.For more information, see Events and Events.

Generar múltiples eventosRaising Multiple Events

Si la clase genera varios eventos, el compilador genera un campo por cada instancia de delegado de eventos.If your class raises multiple events, the compiler generates one field per event delegate instance. Si el número de eventos es alto, es posible que el costo de almacenamiento de un campo por delegado no sea aceptable.If the number of events is large, the storage cost of one field per delegate may not be acceptable. Para estos casos, .NET Framework dispone de propiedades de evento que se pueden usar con otra estructura de datos (de elección propia) para almacenar los delegados de eventos.For those situations, the .NET Framework provides event properties that you can use with another data structure of your choice to store event delegates.

Las propiedades de evento están compuestas de declaraciones de evento acompañadas de descriptores de acceso de evento.Event properties consist of event declarations accompanied by event accessors. Los descriptores de acceso de eventos son métodos que se definen para agregar o quitar instancias de delegados de eventos de la estructura de datos de almacenamiento.Event accessors are methods that you define to add or remove event delegate instances from the storage data structure. Hay que tener en cuenta que 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.Note that event properties are slower than event fields, because each event delegate must be retrieved before it can be invoked. La memoria y la velocidad se ven afectadas.The trade-off is between memory and speed. Si la clase define muchos eventos que no se provocan con frecuencia, es posible que desee implementar propiedades de evento.If your class defines many events that are infrequently raised, you will want to implement event properties. Para más información, consulte Cómo: Controlar varios eventos mediante propiedades de eventos.For more information, see How to: Handle Multiple Events Using Event Properties.

TitleTitle DescriptionDescription
Cómo: Provocar y utilizar eventosHow to: Raise and Consume Events Contiene ejemplos de cómo generar y consumir eventos.Contains examples of raising and consuming events.
Cómo: Controlar varios eventos mediante propiedades de eventosHow to: Handle Multiple Events Using Event Properties Muestra cómo utilizar propiedades de evento para controlar varios eventos.Shows how to use event properties to handle multiple events.
Modelo de diseño de observadorObserver Design Pattern Describe el patrón de diseño que permite que un suscriptor se registre con un proveedor y reciba notificaciones de dicho proveedor.Describes the design pattern that enables a subscriber to register with, and receive notifications from, a provider.
Cómo: Consumir eventos en una aplicación de formularios Web FormsHow to: Consume Events in a Web Forms Application Muestra cómo controlar un evento generado por un control de formularios Web Forms.Shows how to handle an event that is raised by a Web Forms control.

Vea tambiénSee Also

EventHandler
EventHandler<TEventArgs>
EventArgs
Delegate
Introducción a eventos y eventos enrutados (aplicaciones de UWP)Events and routed events overview (UWP apps)
Eventos (Visual Basic)Events (Visual Basic)
Eventos (Guía de programación de C#)Events (C# Programming Guide)