Share via


Información general sobre eventos adjuntos

El Lenguaje de marcado de aplicaciones extensible (XAML) define un componente de lenguaje y un tipo de evento denominado evento adjunto. El concepto de un evento adjunto permite agregar un controlador de un evento determinado a un elemento arbitrario, en lugar de agregarlo a un elemento que realmente define o hereda el evento. En este caso, ni el objeto que genera potencialmente el evento ni la instancia de control del destino definen ni "poseen" de otro modo el evento.

Requisitos previos

En este tema se da por supuesto que ha leído Información general sobre eventos enrutados y XAML en WPF.

Sintaxis de los eventos adjuntos

Los eventos adjuntos tienen un modelo de codificación y una sintaxis XAML que el código de respaldo debe usar para admitir el uso de eventos adjuntos.

En la sintaxis XAML, se especifica el evento adjunto no solo por su nombre de evento, sino por su tipo de propiedad y el nombre de evento, separados por un punto (.). Dado que el nombre del evento está calificado con el nombre de su tipo de propiedad, la sintaxis del evento adjunto permite que cualquier evento adjunto se adjunte a cualquier elemento del que se pueda crear una instancia.

Por ejemplo, la siguiente es la sintaxis de XAML para adjuntar un controlador a un evento adjunto NeedsCleaning personalizado:

<aqua:Aquarium Name="theAquarium" Height="600" Width="800" aqua:AquariumFilter.NeedsCleaning="WashMe"/>

Observe el prefijo aqua:, que, en este caso, es necesario porque el evento adjunto es un evento personalizado que procede de un atributo xmlns asignado personalizado.

Cómo implementa WPF los eventos adjuntos

En WPF, los eventos adjuntos están respaldados por un campo RoutedEvent y se enrutan a través del árbol después de generarse. Normalmente, el origen del evento adjunto (el objeto que genera el evento) es un origen del sistema o del servicio y, por tanto, el objeto que ejecuta el código que genera el evento no forma parte directamente del árbol de elementos.

Escenarios de eventos adjuntos

En WPF, los eventos adjuntos están presentes en determinadas áreas de características, donde existe abstracción de nivel de servicio, como sucede con los eventos que habilita la clase estática Mouse o la clase Validation. Las clases que interactúan con el servicio o lo usan pueden emplear el evento de la sintaxis del evento adjunto, o bien pueden optar por exponer el evento adjunto como un evento enrutado que forme parte de cómo la clase integra las capacidades del servicio.

Aunque WPF define varios eventos adjuntos, los escenarios donde usará o controlará el evento adjunto directamente son muy limitados. Generalmente, el evento adjunto cumple un propósito de arquitectura, pero se reenvía posteriormente a un evento enrutado no adjunto (respaldado por un "contenedor" de eventos de CLR).

Por ejemplo, el evento adjunto subyacente Mouse.MouseDown puede controlarse más fácilmente en cualquier UIElement usando MouseDown en ese UIElement en lugar de lidiar con la sintaxis del evento adjunto ya sea en XAML o en el código. El evento adjunto cumple un propósito de la arquitectura porque permite la expansión futura de los dispositivos de entrada. El hipotético dispositivo solo necesitaría iniciar Mouse.MouseDown para simular la entrada del mouse, y no necesitaría derivar de Mouse para hacerlo. No obstante, este escenario implica el control de código de los eventos, y el control de XAML del evento adjunto no es importante para este escenario.

Control de un evento adjunto en WPF

El proceso para controlar un evento adjunto y el código del controlador que se va a escribir son, básicamente, los mismos que para un evento enrutado.

En general, un evento adjunto de WPF no es muy diferente de un evento enrutado de WPF. Las diferencias se encuentran en cómo se origina el evento y en cómo lo expone una clase como un miembro (lo que también afecta a la sintaxis del controlador XAML).

Sin embargo, como se indicó anteriormente, los eventos adjuntos de WPF existentes no están diseñados especialmente para el control en WPF. Más a menudo, el propósito del evento es habilitar un elemento compuesto para notificar un estado a un elemento primario en la composición, en cuyo caso el evento se genera normalmente en el código y también se basa en el control de clases de la clase primaria pertinente. Por ejemplo, se espera que los elementos dentro de Selector inicien el evento adjunto Selected, que luego es controlado por la clase Selector y luego potencialmente convertido por la clase Selector en un evento enrutado diferente, SelectionChanged. Para obtener más información, consulte Marcar eventos enrutados como controlados y control de clases.

Definición de eventos adjuntos propios como eventos enrutados

Si realiza la derivación de clases base de WPF comunes, puede implementar sus propios eventos adjuntos incluyendo determinados métodos de patrón en la clase y usando métodos de utilidad que ya están presentes en las clases base.

El patrón es el siguiente:

  • Un método AddEventNameHandler con dos parámetros. El primer parámetro es la instancia a la que se añade el controlador de eventos. El segundo parámetro es el controlador de eventos a añadir. El método debe ser public y static, sin ningún valor devuelto.

  • Un método RemoveEventNameHandler con dos parámetros. El primer parámetro es la instancia de la que se elimina el controlador de eventos. El segundo parámetro es el controlador de eventos a eliminar. El método debe ser public y static, sin ningún valor devuelto.

El método del descriptor de acceso AddEventNameHandler facilita el procesamiento de XAML cuando los atributos del controlador de eventos adjuntos se declaran en un elemento. Los métodos AddEventNameHandler y RemoveEventNameHandler también permiten el acceso de código al almacén del controlador de eventos para el evento adjunto.

Este patrón general no es aún lo suficientemente preciso para la implementación práctica en un marco, ya que cualquier implementación determinada del lector de XAML puede tener esquemas diferentes para identificar eventos subyacentes en el lenguaje y la arquitectura secundarios. Esta es una de las razones por las que WPF implementa eventos adjuntos como eventos enrutados; el identificador que se usa para un evento (RoutedEvent) ya está definido por el sistema de eventos de WPF. Además, el enrutamiento de un evento es una extensión natural de la implementación en el concepto de nivel de lenguaje de XAML de un evento adjunto.

La implementación AddEventNameHandler de un evento adjunto de WPF consiste en llamar a AddHandler con el evento enrutado y el controlador como argumentos.

Esta estrategia de implementación y el sistema de eventos enrutados en general restringen el control de eventos adjuntos a las clases derivadas UIElement o a las clases derivadas ContentElement, porque solo esas clases tienen implementaciones de AddHandler.

Por ejemplo, el código siguiente define el evento adjunto de NeedsCleaning en la clase propietaria Aquarium, mediante la estrategia de declarar un evento adjunto como un evento enrutado que ofrecen los eventos adjuntos de WPF.

public static readonly RoutedEvent NeedsCleaningEvent = EventManager.RegisterRoutedEvent("NeedsCleaning", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AquariumFilter));
public static void AddNeedsCleaningHandler(DependencyObject d, RoutedEventHandler handler)
{
    UIElement uie = d as UIElement;
    if (uie != null)
    {
        uie.AddHandler(AquariumFilter.NeedsCleaningEvent, handler);
    }
}
public static void RemoveNeedsCleaningHandler(DependencyObject d, RoutedEventHandler handler)
{
    UIElement uie = d as UIElement;
    if (uie != null)
    {
        uie.RemoveHandler(AquariumFilter.NeedsCleaningEvent, handler);
    }
}
Public Shared ReadOnly NeedsCleaningEvent As RoutedEvent = EventManager.RegisterRoutedEvent("NeedsCleaning", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(AquariumFilter))
Public Shared Sub AddNeedsCleaningHandler(ByVal d As DependencyObject, ByVal handler As RoutedEventHandler)
    Dim uie As UIElement = TryCast(d, UIElement)
    If uie IsNot Nothing Then
        uie.AddHandler(AquariumFilter.NeedsCleaningEvent, handler)
    End If
End Sub
Public Shared Sub RemoveNeedsCleaningHandler(ByVal d As DependencyObject, ByVal handler As RoutedEventHandler)
    Dim uie As UIElement = TryCast(d, UIElement)
    If uie IsNot Nothing Then
        uie.RemoveHandler(AquariumFilter.NeedsCleaningEvent, handler)
    End If
End Sub

Tenga en cuenta que el método usado para establecer el campo de identificador del evento adjunto, RegisterRoutedEvent, es, en realidad, el mismo método que se usa para registrar un evento enrutado no adjunto. Todos los eventos adjuntos y eventos enrutados se registran en un almacén interno centralizado. Esta implementación del almacén de eventos permite la consideración conceptual de "eventos como una interfaz" que se describe en Información general sobre eventos enrutados.

Generación de un evento adjunto de WPF

Normalmente, no es necesario generar eventos adjuntos definidos de WPF a partir del código. Estos eventos siguen el modelo conceptual general de "servicio" y las clases de servicio, como InputManager, son responsables de generar los eventos.

Sin embargo, si está definiendo un evento adjunto personalizado basado en el modelo WPF de basar los eventos adjuntos en RoutedEvent, puede utilizar RaiseEvent para iniciar un evento adjunto desde cualquier UIElement o ContentElement. La generación de un evento enrutado (adjunto o no) requiere que se declare un elemento determinado del árbol de elementos como el origen de eventos; ese origen se notifica como el autor de la llamada a RaiseEvent. Determinar qué elemento se notifica como el origen del árbol es responsabilidad del servicio.

Vea también