Compartir a través de


Introducción a eventos enrutados

Los desarrolladores de aplicaciones y autores de componentes de Windows Presentation Foundation (WPF) pueden usar eventos enrutados para propagar eventos a través de un árbol de elementos e invocar controladores de eventos en varios agentes de escucha del árbol. Estas características no se encuentran en eventos de Common Language Runtime (CLR). Varios de los eventos en WPF son eventos enrutados, como ButtonBase.Click. En este artículo se describen los conceptos básicos de eventos enrutados y se ofrecen instrucciones sobre cuándo y cómo responder a eventos enrutados.

Prerrequisitos

En este artículo se presupone un conocimiento básico de Common Language Runtime (CLR), la programación orientada a objetos y cómo el diseño de elementos WPF se puede conceptualizar como un árbol. Para seguir los ejemplos de este artículo, le ayuda si está familiarizado con el lenguaje de marcado extensible de aplicaciones (XAML) y sabe cómo escribir aplicaciones WPF.

¿Qué es un evento enrutado?

Puede considerar eventos enrutados desde una perspectiva funcional o de implementación:

  • Desde una perspectiva funcional, un evento enrutado es un tipo de evento que puede invocar manejadores en varios oyentes en un árbol de elementos, no solo en la fuente del evento. Un agente de escucha de eventos es el elemento donde se adjunta e invoca un controlador de eventos. Un origen de eventos es el elemento o objeto que generó originalmente un evento.

  • Desde una perspectiva de implementación , un evento enrutado es un evento registrado con el sistema de eventos de WPF, respaldado por una instancia de la RoutedEvent clase y procesado por el sistema de eventos WPF. Normalmente, un evento enrutado se implementa con un "contenedor" de evento CLR para habilitar la asociación de controladores en XAML y en código subyacente como lo haría con un evento CLR.

Las aplicaciones WPF suelen contener muchos elementos, que se declararon en XAML o bien se instanciaron en el código. Los elementos de una aplicación existen dentro de su árbol de elementos. Dependiendo de cómo se define un evento enrutado, cuando se genera el evento en un elemento de origen:

  • Se propaga a través del árbol de elementos del elemento de origen al elemento raíz, que suele ser una página o ventana.
  • Desciende a través del árbol de elementos desde el elemento raíz hasta el elemento de origen.
  • No viaja por el árbol de elementos y solo se produce en el elemento de origen.

Tenga en cuenta el siguiente árbol de elementos parcial:

<Border Height="30" Width="200" BorderBrush="Gray" BorderThickness="1">
    <StackPanel Background="LightBlue" Orientation="Horizontal" Button.Click="YesNoCancelButton_Click">
        <Button Name="YesButton">Yes</Button>
        <Button Name="NoButton">No</Button>
        <Button Name="CancelButton">Cancel</Button>
    </StackPanel>
</Border>

El árbol de elementos se representa como se muestra:

Árbol de elementos XAML con tres botones: Sí, No y Cancelar.

Cada uno de los tres botones es un origen de eventos potencial Click . Cuando se hace clic en uno de los botones, genera el Click evento que se propaga del botón al elemento raíz. Los Button elementos y Border no tienen controladores de eventos asociados, pero StackPanel sí . Posiblemente otros elementos superiores en el árbol que no se muestran también tienen Click controladores de eventos adjuntos. Cuando el Click evento llega al StackPanel elemento, el sistema de eventos wpF invoca el YesNoCancelButton_Click controlador que está asociado a él. La ruta de evento del Click evento en el ejemplo es: Button ->StackPanel ->Border -> elementos primarios sucesivos.

Nota:

El elemento que generó originalmente un evento enrutado se identifica como en RoutedEventArgs.Source los parámetros del controlador de eventos. El agente de escucha de eventos es el elemento al que se adjunta y donde se invoca el controlador de eventos, y se identifica como el remitente en los parámetros del controlador de eventos.

Escenarios de nivel superior para eventos enrutados

Estos son algunos de los escenarios que motivan el concepto de evento enrutado y lo distinguen de un evento CLR típico:

  • Composición y encapsulación de controles: varios controles de WPF tienen un modelo de contenido enriquecido. Por ejemplo, puede colocar una imagen dentro de Button, lo que extiende eficazmente el árbol visual del botón. Sin embargo, la imagen agregada no debe afectar al comportamiento de detección de colisiones del botón, que debe responder cuando un usuario hace clic en los píxeles de la imagen.

  • Puntos de conexión del controlador singular: puedes registrar un controlador para el evento de Click cada botón, pero con eventos enrutados puedes adjuntar un único controlador, como se muestra en el ejemplo XAML anterior. Esto le permite cambiar el árbol de elementos bajo el controlador singular, como agregar o quitar más botones, sin tener que registrar el evento de Click cada botón. Cuando se genera el evento, la Click lógica del controlador puede determinar de dónde procede el evento. El siguiente controlador, especificado en el árbol de elementos XAML mostrado anteriormente, contiene esa lógica:

    private void YesNoCancelButton_Click(object sender, RoutedEventArgs e)
    {
        FrameworkElement sourceFrameworkElement = e.Source as FrameworkElement;
        switch (sourceFrameworkElement.Name)
        {
            case "YesButton":
                // YesButton logic.
                break;
            case "NoButton":
                // NoButton logic.
                break;
            case "CancelButton":
                // CancelButton logic.
                break;
        }
        e.Handled = true;
    }
    
    Private Sub YesNoCancelButton_Click(sender As Object, e As RoutedEventArgs)
        Dim frameworkElementSource As FrameworkElement = TryCast(e.Source, FrameworkElement)
    
        Select Case frameworkElementSource.Name
            Case "YesButton"
                ' YesButton logic.
            Case "NoButton"
                ' NoButton logic.
            Case "CancelButton"
                ' CancelButton logic.
        End Select
    
        e.Handled = True
    End Sub
    
  • Control de clases: los eventos enrutados admiten un controlador de eventos de clase que se define en una clase. Los controladores de clase controlan un evento antes de cualquier controlador de instancia para el mismo evento en cualquier instancia de la clase .

  • Hacer referencia a un evento sin reflexión: cada evento enrutado crea un RoutedEvent identificador de campo para proporcionar una técnica de identificación de eventos sólida que no requiere reflexión estática o en tiempo de ejecución para identificar el evento.

Cómo se implementan los eventos enrutados

Un evento enrutado es un evento registrado con el sistema de eventos de WPF, respaldado por una instancia de la RoutedEvent clase y procesado por el sistema de eventos WPF. La RoutedEvent instancia, obtenida del registro, se almacena normalmente como public static readonly miembro de la clase que la registró. Esa clase se denomina la clase "propietario" del evento. Normalmente, un evento enrutado implementa un evento CLR llamado de manera idéntica como "envoltorio". El contenedor de eventos CLR contiene los descriptores de acceso add y remove para habilitar la asociación de controladores en XAML y en el código detrás a través de la sintaxis de eventos específica del lenguaje. Los descriptores de acceso add y remove invalidan su implementación CLR y llaman a los métodos del evento enrutado AddHandler y RemoveHandler. El mecanismo de respaldo y conexión de eventos enrutados es conceptualmente similar al modo en que una propiedad de dependencia es una propiedad CLR respaldada por la DependencyProperty clase y registrada con el sistema de propiedades de WPF.

En el ejemplo siguiente se registra el Tap evento enrutado, se almacena la instancia devuelta RoutedEvent e se implementa un contenedor de eventos CLR.

// Register a custom routed event using the Bubble routing strategy.
public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
    name: "Tap",
    routingStrategy: RoutingStrategy.Bubble,
    handlerType: typeof(RoutedEventHandler),
    ownerType: typeof(CustomButton));

// Provide CLR accessors for adding and removing an event handler.
public event RoutedEventHandler Tap
{
    add { AddHandler(TapEvent, value); }
    remove { RemoveHandler(TapEvent, value); }
}
' Register a custom routed event using the Bubble routing strategy.
Public Shared ReadOnly TapEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
    name:="Tap",
    routingStrategy:=RoutingStrategy.Bubble,
    handlerType:=GetType(RoutedEventHandler),
    ownerType:=GetType(CustomButton))

' Provide CLR accessors for adding and removing an event handler.
Public Custom Event Tap As RoutedEventHandler
    AddHandler(value As RoutedEventHandler)
        [AddHandler](TapEvent, value)
    End AddHandler

    RemoveHandler(value As RoutedEventHandler)
        [RemoveHandler](TapEvent, value)
    End RemoveHandler

    RaiseEvent(sender As Object, e As RoutedEventArgs)
        [RaiseEvent](e)
    End RaiseEvent
End Event

Estrategias de enrutamiento

Los eventos enrutados usan una de las tres estrategias de enrutamiento:

  • Burbujeo: inicialmente, se invocan controladores de eventos en el origen del evento. A continuación, el evento enrutado se dirige a los elementos primarios uno tras otro, invocando sus controladores de eventos de manera secuencial, hasta que llega a la raíz del árbol de elementos. La mayoría de los eventos enrutados usan la estrategia de enrutamiento de burbujeo. Los eventos enrutados de burbujeo se suelen usar para notificar cambios de entrada o estado de controles compuestos u otros elementos de la interfaz de usuario.

  • Tunelización: inicialmente, se invocan controladores de eventos en la raíz del árbol de elementos. A continuación, el evento enrutado se enruta a los elementos secundarios sucesivos, invocando sus controladores de eventos a su vez, hasta que llega al origen del evento. Los eventos que siguen a una ruta de tunelización también se conocen como eventos de versión preliminar . Los eventos de entrada de WPF generalmente se implementan como pares de vista previa y burbujeo.

  • Directo: solo se invocan controladores de eventos en el origen del evento. Esta estrategia de no enrutamiento es análoga a los eventos del marco de interfaz de usuario de Windows Forms, que son eventos CLR estándar. A diferencia de los eventos CLR, los eventos enrutados directos admiten el control de clases y se pueden usar mediante EventSetters y EventTriggers.

¿Por qué usar eventos enrutados?

Como desarrollador de aplicaciones, no siempre es necesario saber o preocuparse de que el evento que controla se implementa como un evento enrutado. Los eventos enrutados tienen un comportamiento especial, pero ese comportamiento es en gran medida invisible si controla un evento en el elemento que lo generó. Sin embargo, los eventos enrutados son relevantes cuando se desea adjuntar un controlador de eventos a un elemento primario para controlar los eventos generados por elementos secundarios, como dentro de un control compuesto.

Los escuchadores de eventos enrutados no necesitan que los eventos enrutados que manejan sean miembros de su clase. Cualquiera UIElement o ContentElement puede ser un agente de escucha de eventos para cualquier evento enrutado. Dado que los elementos visuales derivan de UIElement o ContentElement, puede usar eventos enrutados como una "interfaz" conceptual que admita el intercambio de información de eventos entre distintos elementos de una aplicación. El concepto de "interfaz" para eventos enrutados es especialmente aplicable a los eventos de entrada.

Los eventos enrutados admiten el intercambio de información de evento entre elementos en la ruta del evento porque cada escuchador tiene acceso a la misma instancia de datos de evento. Si un elemento cambia algo en los datos del evento, ese cambio es visible para los elementos posteriores de la ruta del evento.

Además del aspecto de enrutamiento, puede optar por implementar un evento enrutado en lugar de un evento CLR estándar por estas razones:

  • Algunas características de plantillas y estilos de WPF, como EventSetters y EventTriggers, requieren que el evento al que se hace referencia sea un evento enrutado.

  • Los eventos enrutados admiten controladores de eventos de clase que controlan un evento antes de cualquier controlador de instancia para el mismo evento en cualquier instancia de la clase de agente de escucha. Esta característica es útil en el diseño de controles porque el controlador de clases puede aplicar comportamientos de clase controlados por eventos que un controlador de instancia no puede suprimir accidentalmente.

Adjuntar e implementar un controlador de eventos enrutado

En XAML, adjuntas un controlador de eventos a un elemento declarando el nombre del evento como un atributo en el elemento de escucha de eventos. El valor del atributo es el nombre del método del controlador. El método de controlador debe implementarse en la clase parcial de código subyacente para la página XAML. El agente de escucha de eventos es el elemento donde se adjunta e invoca el controlador de eventos.

Para un evento que es un miembro (heredado o de otro modo) de la clase de agente de escucha, puede adjuntar un controlador de la siguiente manera:

<Button Name="Button1" Click="Button_Click">Click me</Button>

Si el evento no es miembro de la clase del agente de escucha, debe usar el nombre de evento completo en forma de <owner type>.<event name>. Por ejemplo, dado que la clase StackPanel no implementa el evento Click, para asociar un controlador a StackPanel para un evento Click que se propaga hasta llegar a ese elemento, deberá usar la sintaxis de nombre de evento calificado.

<StackPanel Name="StackPanel1" Button.Click="Button_Click">
    <Button>Click me</Button>
</StackPanel>

La firma del método del controlador de eventos en el código subyacente debe coincidir con el tipo de delegado para el evento enrutado. El sender parámetro del RoutedEventHandler delegado para el Click evento especifica el elemento al que está asociado el controlador de eventos. El args parámetro del RoutedEventHandler delegado contiene los datos del evento. Una implementación de código subyacente compatible para el Button_Click controlador de eventos puede ser:

private void Button_Click(object sender, RoutedEventArgs e)
{
    // Click event logic.
}
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
    ' Click event logic.
End Sub

Aunque RoutedEventHandler es el delegado básico del controlador de eventos enrutado, algunos controles o escenarios de implementación requieren delegados diferentes que admiten datos de eventos más especializados. Por ejemplo, para el DragEnter evento enrutado, el controlador debe implementar el DragEventHandler delegado. Al hacerlo, el código del controlador puede acceder a la DragEventArgs.Data propiedad en los datos del evento, que contiene el contenido del portapapeles de la operación de arrastre.

La sintaxis XAML para agregar controladores de eventos enrutados es la misma que para los controladores de eventos CLR estándar. Para obtener más información sobre cómo agregar controladores de eventos en XAML, consulta XAML en WPF. Para obtener un ejemplo completo de cómo adjuntar un controlador de eventos a un elemento mediante XAML, consulta Cómo controlar un evento enrutado.

Para adjuntar un controlador de eventos para un evento enrutado a un elemento mediante código, normalmente tiene dos opciones:

  • Llame directamente al método AddHandler. Los controladores de eventos enrutados siempre se pueden conectar de esta forma. En este ejemplo se adjunta un Click controlador de eventos a un botón mediante el AddHandler método :

    Button1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
    
    Button1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
    

    Para adjuntar un controlador para el evento del Click botón a otro elemento de la ruta del evento, como un StackPanel que se llama StackPanel1:

    StackPanel1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
    
    StackPanel1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
    
  • Si el evento enrutado implementa un contenedor de eventos CLR, use la sintaxis de eventos específica del lenguaje para agregar controladores de eventos igual que lo haría para un evento CLR estándar. La mayoría de los eventos enrutados existentes de WPF implementan el envoltorio CLR, permitiendo la sintaxis de eventos específica del lenguaje. En este ejemplo se asocia un Click controlador de eventos a un botón mediante la sintaxis específica del lenguaje:

    Button1.Click += Button_Click;
    
    AddHandler Button1.Click, AddressOf Button_Click
    

Para obtener un ejemplo de cómo adjuntar un controlador de eventos en el código, vea Cómo agregar un controlador de eventos mediante código. Si está codificando en Visual Basic, también puede usar la Handles palabra clave para agregar controladores como parte de las declaraciones del controlador. Para obtener más información, vea Control de eventos de Visual Basic y WPF.

El concepto de controlado

Todos los eventos enrutados comparten una clase base común para los datos de eventos, que es la RoutedEventArgs clase . La RoutedEventArgs clase define la propiedad booleana Handled . El propósito de la Handled propiedad es permitir que cualquier controlador de eventos a lo largo de la ruta de eventos marque el evento enrutado como controlado. Para marcar un evento como controlado, establezca el valor de Handled a true en el código del controlador de eventos.

El valor de Handled afecta a cómo se procesa un evento enrutado a medida que viaja a lo largo de la ruta del evento. Si Handled está true en los datos de eventos compartidos de un evento enrutado, los controladores que están adjuntos a otros elementos en la continuación de la ruta del evento normalmente no se invocarán para esa instancia particular del evento. Para los escenarios más comunes de gestión de eventos, marcar un evento como manejado bloquea eficazmente a los controladores de clase o instancia posteriores en la ruta del evento para que no respondan a esa instancia específica del evento. Sin embargo, en casos poco frecuentes en los que necesita que el controlador de eventos responda a eventos enrutados marcados como controlados, puede hacer lo siguiente:

El concepto de Handled podría afectar a cómo diseñar la aplicación y codificar los controladores de eventos. Puede conceptualizar Handled como un protocolo simple para el procesamiento de eventos enrutados. La forma en que utilices este protocolo depende de ti, pero el uso esperado del parámetro Handled es:

  • Si un evento enrutado se marca como controlado, no es necesario controlarlo de nuevo por otros elementos a lo largo de la ruta.

  • Si un evento enrutado no está marcado como manejado, los oyentes anteriores en la ruta del evento no tienen un manejador para el evento, o ninguno de los manejadores registrados respondió al evento de una forma que justifique marcar el evento como manejado. Los controladores en el oyente actual tienen tres posibles cursos de acción:

    • No haga nada. El evento permanece sin gestionar y se enruta al siguiente oyente del árbol.

    • Ejecute código en respuesta al evento, pero no en una medida en que justifica marcar el evento como controlado. El evento permanece sin gestionar y se enruta al siguiente oyente del árbol.

    • Ejecute código en respuesta al evento, en una medida en que justifica marcar el evento como controlado. Marque el evento como gestionado en los datos del evento. El evento continúa encaminando al siguiente escucha en el árbol, pero la mayoría de las escuchas no invocarán otros controladores. La excepción son oyentes con controladores que se registraron específicamente con handledEventsToo configurado a true.

Para obtener más información sobre el control de eventos enrutados, vea Marcar eventos enrutados como controlados y control de clases.

Aunque los desarrolladores que solo controlan un evento enrutado de propagación en el objeto que lo generó podrían no preocuparse por otros agentes de escucha, es recomendable marcar el evento como controlado de todos modos. Al hacerlo, se evitan efectos secundarios imprevistos si un elemento más a lo largo de la ruta de eventos tiene un controlador para el mismo evento enrutado.

Controladores de clases

Los controladores de eventos enrutados pueden ser controladores de instancia o controladores de clase . Los controladores de clase para una clase determinada se invocan antes de que cualquier controlador de instancia responda al mismo evento en cualquier instancia de esa clase. Debido a este comportamiento, cuando los eventos enrutados se marcan como controlados, a menudo se marcan como tales dentro de los controladores de clase. Hay dos tipos de controladores de clases:

Algunos controles WPF tienen manejo de clases inherente para determinados eventos enrutados. El control de clases puede dar la apariencia externa de que el evento enrutado no se genera nunca, pero en realidad se marca como controlado por un controlador de clases. Si necesita que su manejador de eventos responda al evento gestionado, puede registrar su manejador con handledEventsToo establecido en true. Para obtener más información, tanto sobre cómo implementar sus propios manejadores de clases como sobre cómo manejar el control de clases no deseado, consulte Marcar eventos enrutados como manejados y manejo de clases.

Eventos adjuntos en WPF

El lenguaje XAML también define un tipo especial de evento denominado evento adjunto. Los eventos adjuntos se pueden usar para definir un nuevo evento enrutado en una clase que no sea de elemento y generar ese evento en cualquier elemento del árbol. Para ello, debe registrar el evento adjunto como un evento enrutado y proporcionar código de respaldo específico que admita la funcionalidad de eventos adjuntos. Dado que los eventos adjuntos se registran como eventos enrutados, cuando se generan en un elemento, se propagan a través del árbol de elementos.

En la sintaxis XAML, un evento adjunto se especifica mediante su nombre de evento y el tipo de propietario, en forma de <owner type>.<event name>. Dado que el nombre del evento se califica con el nombre de su tipo de propietario, la sintaxis permite que el evento se adjunte a cualquier elemento del que se pueda instanciar. Esta sintaxis también es aplicable a los controladores para eventos enrutados normales que se adjuntan a un elemento arbitrario a lo largo de la ruta del evento. También puede adjuntar controladores para eventos adjuntos en el código de fondo usando el método AddHandler en el objeto al que debe conectarse el controlador.

El sistema de entrada de WPF usa eventos adjuntos ampliamente. Sin embargo, casi la totalidad de esos eventos conectados se presentan como eventos enrutados no asociados equivalentes a través de elementos base. Rara vez usará o gestionará los eventos adjuntos directamente. Por ejemplo, es más fácil controlar el evento adjunto Mouse.MouseDown subyacente en un UIElement a través del evento enrutado equivalente UIElement.MouseDown que mediante la sintaxis de eventos adjunta en XAML o código subyacente.

Para obtener más información sobre los eventos adjuntos en WPF, vea Información general sobre eventos adjuntos.

Nombres de eventos completos en XAML

La <owner type>.<event name> sintaxis califica un nombre de evento con el nombre de su tipo de propietario. Esta sintaxis permite adjuntar un evento a cualquier elemento, no solo a los elementos que implementan el evento como miembro de su clase. La sintaxis es aplicable al adjuntar controladores en XAML para eventos adjuntos o eventos enrutados en elementos arbitrarios a lo largo de la ruta de eventos. Tenga en cuenta el escenario en el que desea adjuntar un controlador a un elemento primario para controlar los eventos enrutados generados en elementos secundarios. Si el elemento primario no tiene el evento enrutado como miembro, deberá usar la sintaxis de nombre de evento calificado. Por ejemplo:

<StackPanel Name="StackPanel1" Button.Click="Button_Click">
    <Button>Click me</Button>
</StackPanel>

En el ejemplo, el elemento padre que actúa como escucha al que se agrega el controlador de eventos es un StackPanel. Sin embargo, el Click evento enrutado se implementa y genera en la ButtonBase clase y está disponible para la clase mediante la herencia de la Button clase. Aunque la Button clase "posee" el Click evento, el sistema de eventos enrutados permite que los controladores de cualquier evento enrutado se asocien a cualquier UIElement oyente de instancia o ContentElement que, de lo contrario, pueda tener controladores para un evento CLR. El espacio de nombres predeterminado xmlns para estos nombres de atributo de evento calificado suele ser el espacio de nombres WPF xmlns predeterminado, pero también puede especificar espacios de nombres prefijos para eventos enrutados personalizados. Para obtener más información sobre xmlns, consulte espacios de nombres XAML y mapeo de espacios de nombres para XAML de WPF.

Eventos de entrada de WPF

Una aplicación frecuente de eventos enrutados dentro de la plataforma WPF es para eventos de entrada

Los eventos de entrada de WPF que vienen en pares se implementan de manera que una sola acción de usuario desde un dispositivo de entrada, como un clic del botón del ratón, desencadene en secuencia los eventos enrutados de vista previa y de burbujeo. En primer lugar, el evento de vista previa se activa y completa su ruta. Al finalizar el evento de previsualización, se genera el evento de propagación y se completa su ruta. La llamada al método RaiseEvent en la clase que implementa y que genera el evento burbujeante reutiliza los datos del evento de vista previa para el evento burbujeante.

Un evento de entrada de vista previa marcado como controlado no invocará ningún controlador de eventos registrado normalmente durante el resto de la ruta de vista previa y no se generará el evento de propagación emparejado. Este comportamiento de control es útil para los diseñadores de controles compuestos que desean que los eventos de entrada basados en pruebas de posicionamiento o los eventos de entrada basados en foco se notifiquen en el nivel superior de su control. Los elementos de nivel superior del control tienen la oportunidad de controlar los eventos de vista previa de los subcomponentes de control para "reemplazarlos" por un evento específico del control de nivel superior.

Para ilustrar cómo funciona el procesamiento de eventos de entrada, tenga en cuenta el siguiente ejemplo de evento de entrada. En la siguiente ilustración de árbol, leaf element #2 es el origen de los eventos pareados de PreviewMouseDown y MouseDown.

Diagrama que muestra cómo fluye el enrutamiento de eventos de un elemento raíz a otros elementos.

El orden del procesamiento de eventos después de una acción de mouse hacia abajo en el elemento hoja n.º 2 es:

  1. PreviewMouseDown evento de tunelización en el elemento raíz.
  2. PreviewMouseDown evento de tunelización en el elemento intermedio n.º 1.
  3. PreviewMouseDown evento de tunelización en el elemento hoja n.º 2, que es el elemento de origen.
  4. MouseDown evento de burbujeo en el elemento hoja número 2, que es el elemento de origen.
  5. MouseDown evento de burbujeo en el elemento intermedio n.º 1.
  6. MouseDown evento de burbujeo en el elemento raíz.

El delegado del controlador de eventos enrutado proporciona referencias tanto al objeto que generó el evento como al objeto en el que se invocó el controlador. El objeto que generó originalmente el evento se notifica mediante la Source propiedad en los datos del evento. El parámetro remitente notifica el objeto donde se invocó el controlador. Para cualquier instancia de evento enrutado, el objeto que generó el evento no cambia mientras el evento atraviesa el árbol de elementos, pero sender sí cambia. En los pasos 3 y 4 del diagrama anterior, el Source y el sender son el mismo objeto.

Si el controlador de eventos de entrada completa la lógica específica de la aplicación necesaria para abordar el evento, debe marcar el evento de entrada como controlado. Normalmente, una vez que un evento de entrada está marcado Handled, no se invocan manejadores más a lo largo de la ruta de eventos. Sin embargo, los controladores de eventos de entrada registrados con el parámetro handledEventsToo establecido en true se invocarán incluso cuando el evento está marcado como manejado. Para obtener más información, consulte Vista previa de eventos y Eventos enrutados marcados como controlados y control de clases.

El concepto de pares de eventos de vista previa y de propagación, con datos de eventos compartidos y la generación secuencial del evento de vista previa, luego el evento de propagación, aplica únicamente a algunos eventos de entrada de WPF y no a todos los eventos enrutados. Si implementa su propio evento de entrada para abordar un escenario avanzado, considere la posibilidad de seguir el enfoque del par de eventos de entrada de WPF.

Si va a implementar su propio control compuesto que responde a eventos de entrada, considere la posibilidad de usar eventos de vista previa para suprimir y reemplazar los eventos de entrada generados en subcomponentes con un evento de nivel superior que representa el control completo. Para obtener más información, vea Marcar eventos enrutados como controlados y control de clases.

Para obtener más información sobre el sistema de entrada de WPF y cómo interactúan las entradas y los eventos en escenarios de aplicación típicos, consulte Introducción a la entrada.

EventSetters y EventTriggers

En los estilos de marcado, puedes incluir la sintaxis de control de eventos XAML declarada previamente mediante .EventSetter Cuando se procesa el XAML, el controlador al que se hace referencia se agrega a la instancia estilizada. Solo puede declarar un EventSetter para un evento enrutado. En el ejemplo siguiente, el método de controlador de eventos al que se hace ApplyButtonStyle referencia se implementa en código subyacente.

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="{x:Type Button}">
            <EventSetter Event="Click" Handler="ApplyButtonStyle"/>
        </Style>
    </StackPanel.Resources>
    <Button>Click me</Button>
    <Button Click="Button_Click">Click me</Button>
</StackPanel>

Es probable que el Style nodo ya contenga otra información de estilo que pertenezca a los controles del tipo especificado y que el hecho de que forme EventSetter parte de esos estilos promueve la reutilización del código incluso en el nivel de marcado. Además, un EventSetter abstrae los nombres de método para los controladores fuera de la aplicación general y el marcado de página.

Otra sintaxis especializada que combina las características de eventos y animaciones enrutadas de WPF es una EventTrigger. Al igual que con EventSetter, solo puede declarar un EventTrigger para un evento enrutado. Normalmente, un EventTrigger se declara como parte de un estilo, pero un EventTrigger se puede declarar en elementos de nivel de página como parte de la colección Triggers o en un ControlTemplate. EventTrigger permite especificar un Storyboard que se ejecuta siempre que un evento enrutado llega a un elemento en su ruta que declara un EventTrigger para ese evento. La ventaja de un EventTrigger sobre simplemente manejar el evento y hacer que inicie un guión gráfico existente es que EventTrigger proporciona un mejor control sobre el guión gráfico y su comportamiento en tiempo de ejecución. Para obtener más información, consulte Uso de desencadenadores de eventos para controlar un guión gráfico después de que se inicie.

Más información sobre los eventos enrutados

Puede usar los conceptos e instrucciones de este artículo como punto de partida al crear eventos enrutados personalizados en sus propias clases. Puede respaldar sus eventos personalizados con clases especializadas de datos de eventos y delegados. Un propietario de eventos enrutado puede ser cualquier clase, pero los eventos enrutados deben generarse y controlarse mediante UIElement clases derivadas o ContentElement para que sean útiles. Para obtener más información sobre los eventos personalizados, consulte Creación de un evento enrutado personalizado.

Consulte también