Información general sobre eventos adjuntos
Extensible Application Markup Language (XAML) define un componente de lenguaje y un tipo de evento denominado evento adjunto. El concepto de evento adjunto permite agregar un controlador correspondiente a un evento determinado a un elemento arbitrario, en lugar de al elemento que realmente define o hereda el evento. En este caso, ni el objeto que genera potencialmente el evento ni la instancia de control de destino definen ni "poseen" el evento de ningún modo.
Este tema contiene las secciones siguientes.
- Requisitos previos
- Sintaxis de eventos adjuntos
- Cómo se implementan los eventos adjuntos en WPF
- Escenarios para los eventos adjuntos
- Administrar eventos adjuntos en WPF
- Definir sus propios eventos adjuntos como eventos enrutados
- Generar un evento adjunto de WPF
- Temas relacionados
Requisitos previos
En este tema se supone que el usuario ha leído Información general sobre eventos enrutados y Información general sobre XAML (WPF).
Sintaxis de eventos adjuntos
Los eventos adjuntos tienen una sintaxis XAML y un modelo de codificación que es preciso utilizar en el código de respaldo para admitir el uso de este tipo de eventos.
En la sintaxis XAML, el evento adjunto no se especifica sólo por su nombre de evento, sino por su tipo poseedor y su nombre de evento, separados por un punto (.). Dado que el nombre de evento se certifica con el nombre de su tipo poseedor, la sintaxis de eventos adjuntos permite asociar cualquier evento a cualquier elemento del que se puedan crear instancias.
Por ejemplo, a continuación se muestra la sintaxis XAML para asociar un controlador para un evento adjunto personalizado, NeedsCleaning:
<aqua:Aquarium Name="theAquarium" Height="600" Width="800" aqua:AquariumFilter.NeedsCleaning="WashMe"/>
Observe el prefijo aqua:, que es necesario en este caso porque el evento adjunto es un evento personalizado que procede de un xmlns asignado personalizado.
Cómo se implementan los eventos adjuntos en WPF
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 de servicio; en consecuencia, el objeto que ejecuta el código que genera el evento no forma parte directa del árbol de elementos.
Escenarios para los eventos adjuntos
En WPF, los eventos adjuntos están presentes en algunas áreas de características donde existe la abstracción de nivel de servicio, por ejemplo, para los eventos habilitados por la clase Mouse estática o por la clase Validation. Las clases que interactúan con el servicio o que lo utilizan pueden usar el evento en la sintaxis de eventos adjuntos o bien exponer el evento adjunto como evento enrutado que forma parte de la integración de la clase en las funciones del servicio.
Aunque WPF define varios eventos adjuntos, los escenarios donde los utilizará o controlará directamente son muy limitados. En general, el evento adjunto sirve para algún fin de la arquitectura, pero luego se reenvía a un evento enrutado no asociado (respaldado por un "contenedor" de evento CLR).
Por ejemplo, el evento adjunto Mouse.MouseDown subyacente se puede controlar más fácilmente en cualquier UIElement determinado utilizando MouseDown en ese UIElement en lugar de emplear sintaxis de eventos adjuntos en XAML o en código. El evento adjunto sirve para fines de la arquitectura, porque permite la expansión futura de los dispositivos de entrada. El dispositivo hipotético sólo necesitaría generar Mouse.MouseDown para simular una entrada del mouse y no necesitaría derivar de la clase Mouse para ello. Sin embargo, este escenario implica el control de eventos mediante código, y el control mediante XAML del evento adjunto no es pertinente a este escenario.
Administrar eventos adjuntos en WPF
El proceso de control de eventos adjuntos y el código de controlador que se escribe son, básicamente, iguales que para un evento enrutado.
En general, un evento adjunto de WPF no se diferencia mucho de un evento enrutado de WPF. Las diferencias residen en cómo se origina el evento y en cómo lo expone como miembro una clase (lo que también afecta a la sintaxis de controlador en XAML).
Sin embargo, como se indica anteriormente, los eventos adjuntos de WPF existentes no están destinados en particular al control en WPF. Casi siempre, la finalidad del evento es permitir que un elemento compuesto informe de un estado a un elemento primario en la composición de controles, en cuyo caso el evento se suele generar mediante código y, además, se basa en la administración de clases de la clase primaria pertinente. Por ejemplo, se espera que los elementos de Selector provoquen el evento adjunto Selected, que es administrado por la clase Selector; a continuación, es posible que la clase Selector lo convierta en un evento enrutado diferente, SelectionChanged. Para obtener más información sobre el control de eventos enrutados y la administración de clases, vea Marcar eventos enrutados como controlados y control de clases.
Definir sus propios eventos adjuntos como eventos enrutados
Si deriva de las clases base comunes de WPF, puede implementar sus propios eventos adjuntos incluyendo determinados métodos de modelo en la clase y utilizando métodos de utilidad que ya están presentes en las clases base.
El modelo es el siguiente:
Un método Add*Handler con dos parámetros. El primer parámetro debe identificar el evento y el evento identificado debe coincidir con nombres que tengan * en el nombre de método. El segundo parámetro es el controlador que se va a agregar. El método debe ser público y estático, sin ningún valor devuelto.
Un método Remove*Handler con dos parámetros. El primer parámetro debe identificar el evento y el evento identificado debe coincidir con nombres que tengan * en el nombre de método. El segundo parámetro es el controlador que se va a quitar. El método debe ser público y estático, sin ningún valor devuelto.
El método de descriptor de acceso Add*Handler facilita el procesamiento XAML cuando se declaran atributos de controlador de eventos adjuntos en un elemento. Los métodos Add*Handler y Remove*Handler también permiten el acceso mediante código al almacén de controladores de eventos del evento adjunto.
Este modelo general no es lo bastante preciso para la implementación práctica en un marco de trabajo, porque cada implementación de lector de XAML podría tener esquemas diferentes para identificar los eventos subyacentes en el lenguaje y la arquitectura de respaldo. Esta es una de las razones por las que WPF implementa los eventos adjuntos como eventos enrutados; el identificador que debe utilizarse para un evento (RoutedEvent) ya está definido por el sistema de eventos de WPF. Asimismo, enrutar un evento constituye una extensión natural de la implementación en el concepto de nivel de lenguaje de XAML de un evento adjunto.
La implementación de Add*Handler para un evento adjunto de WPF está compuesto de una llamada a AddHandler con el evento enrutado y el controlador como argumentos.
En general, esta estrategia de implementación y el sistema de eventos enrutados restringen el control de los eventos adjuntos a las clases derivadas de UIElement o de ContentElement, porque sóloo ellas tienen implementaciones de AddHandler.
Por ejemplo, en el código siguiente se define el evento adjunto NeedsCleaning de la clase propietaria Aquarium; para ello se utiliza la estrategia de eventos adjuntos de WPF consistente en declarar el evento adjunto como evento enrutado.
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
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);
}
}
Observe que el método utilizado para establecer el campo de identificador del evento adjunto, RegisterRoutedEvent, es en realidad el mismo método que se utiliza para registrar un evento enrutado no asociado. Tanto los eventos adjuntos como los eventos enrutados se registran en un almacén interno centralizado. Esta implementación de almacén de eventos permite la consideración conceptual de "uso de eventos como interfaces" que se describe en Información general sobre eventos enrutados.
Generar un evento adjunto de WPF
Normalmente, no es necesario generar los eventos adjuntos existentes definidos en WPF mediante código. Estos eventos siguen el modelo conceptual general de "servicio", donde las responsables de generar los eventos son las clases de servicio, como InputManager.
Sin embargo, si define un evento adjunto personalizado basado en el modelo de WPF consistente en basar los eventos adjuntos en eventos enrutados (RoutedEvent), puede utilizar RaiseEvent para generar un evento adjunto de cualquier objeto UIElement o ContentElement. Para generar un evento enrutado (adjunto o no) es preciso declarar un elemento concreto del árbol de elementos como origen del evento; este origen se comunica como llamador del método RaiseEvent. Determinar qué elemento se comunica como origen en el árbol es responsabilidad del servicio.