Información general sobre eventos enrutados

En este tema se describe el concepto de eventos enrutados en Windows Presentation Foundation (WPF). En el tema se define la terminología de los eventos enrutados, se describe cómo se enrutan a través de un árbol de elementos, se resume cómo controlar los eventos enrutados y se explica cómo crear sus propios eventos enrutados personalizados.

Requisitos previos

En este tema se da por supuesto que tiene conocimientos básicos de Common Language Runtime (CLR) y la programación orientada a objetos, así como el concepto de cómo se pueden conceptualizar las relaciones entre los elementos como un WPF árbol. Para seguir los ejemplos de este tema, también debe comprender Lenguaje XAML (Extensible Application Markup Language) y saber cómo escribir páginas o aplicaciones de WPF muy básicas. Para obtener más información, vea Tutorial: Mi primera aplicación de escritorio WPF y XAML en WPF.

¿Qué es un evento enrutado?

Los eventos enrutados se pueden considerar desde dos perspectivas: funcional y de implementación. Aquí se presentan ambas definiciones, dado que algunas personas encuentran que una es más útil que la otra.

Definición funcional: un evento enrutado es un tipo de evento que puede invocar controladores en varios agentes de escucha en un árbol de elementos, en lugar de simplemente en el objeto que ha generado el evento.

Definición de implementación: un evento enrutado es un evento CLR que está respaldo por una instancia de la clase y que el sistema de RoutedEvent Windows Presentation Foundation (WPF) eventos procesa.

Una aplicación típica de WPF contiene muchos elementos. Tanto si se crean en código como si se declaran en XAML, estos elementos se relacionan entre sí a través de un árbol de elementos. En función de la definición del evento, la ruta de eventos puede viajar en cualquiera de las dos direcciones, pero generalmente viaja desde el elemento de origen y, después, "se propaga" en sentido ascendente por el árbol de elementos hasta que llega a la raíz (normalmente una página o una ventana). Es posible que este concepto de propagación le resulte familiar si ha trabajado previamente con el modelo de objetos DHTML.

Considere el siguiente árbol de elementos simple:

<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
  <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
    <Button Name="YesButton" Width="Auto" >Yes</Button>
    <Button Name="NoButton" Width="Auto" >No</Button>
    <Button Name="CancelButton" Width="Auto" >Cancel</Button>
  </StackPanel>
</Border>

Este árbol de elementos genera algo parecido a lo siguiente:

Botones Sí, No y Cancelar

En este árbol de elementos simplificado, el origen de un evento es uno de los elementos y lo que se hizo clic es el primer elemento que tiene la oportunidad de Click Button controlar el Button evento. Pero si no hay ningún controlador asociado a los actos en el evento, el evento se burbujas hacia arriba hasta el elemento primario en el árbol de Button Button elementos, que es StackPanel . Potencialmente, el evento se burbujas en y, a continuación, más allá de la raíz de página Border del árbol de elementos (no se muestra).

En otras palabras, la ruta del evento para este Click evento es:

Botón-->StackPanel-->Borde-->...

Escenarios de nivel superior para los eventos enrutados

A continuación se muestra un breve resumen de los escenarios que motivaron el concepto de evento enrutado y por qué un evento CLR típico no era adecuado para estos escenarios:

Encapsulación y composición de controles: varios controles de WPF tienen un modelo de contenido enriquecido. Por ejemplo, puede colocar una imagen dentro de un , lo que extiende de forma eficaz Button el árbol visual del botón. Sin embargo, la imagen agregada no debe interrumpir el comportamiento de las pruebas de acceso que hace que un botón responda a un de su contenido, incluso si el usuario hace clic en píxeles que forman parte técnicamente de la Click imagen.

Puntos de datos adjuntos de controlador singulares: En Windows forms, tendría que adjuntar el mismo controlador varias veces para procesar eventos que se podrían generar desde varios elementos. Los eventos enrutados le permiten asociar ese controlador una sola vez, tal como se ha mostrado en el ejemplo anterior, y usar la lógica del controlador para determinar el origen del evento si fuera necesario. Por ejemplo, este podría ser el controlador para el XAML mostrado anteriormente:

private void CommonClickHandler(object sender, RoutedEventArgs e)
{
  FrameworkElement feSource = e.Source as FrameworkElement;
  switch (feSource.Name)
  {
    case "YesButton":
      // do something here ...
      break;
    case "NoButton":
      // do something ...
      break;
    case "CancelButton":
      // do something ...
      break;
  }
  e.Handled=true;
}
Private Sub CommonClickHandler(ByVal sender As Object, ByVal e As RoutedEventArgs)
  Dim feSource As FrameworkElement = TryCast(e.Source, FrameworkElement)
  Select Case feSource.Name
    Case "YesButton"
      ' do something here ...
    Case "NoButton"
      ' do something ...
    Case "CancelButton"
      ' do something ...
  End Select
  e.Handled=True
End Sub

Control de clases: los eventos enrutados permiten un controlador estático definido por la clase. Este controlador de clase tiene la oportunidad de controlar un evento antes de que pueda hacerlo cualquiera de los controladores de instancia asociados.

Hacer referencia a un evento sin reflexión: determinadas técnicas de código y de marcado requieren una manera de identificar un evento concreto. Un evento enrutado crea un campo como identificador, que proporciona una sólida técnica de identificación de eventos que no requiere reflexión estática o RoutedEvent en tiempo de ejecución.

Cómo se implementan los eventos enrutados

Un evento enrutado es un evento CLR que está respaldo por una instancia de la RoutedEvent clase y registrado con el sistema de WPF eventos. La instancia obtenida del registro normalmente se conserva como un miembro de campo de la clase que registra y, por tanto, RoutedEvent public static readonly "posee" el evento enrutado. La conexión al evento CLR con el mismo nombre (que a veces se denomina evento "contenedor") se realiza invalidando las implementaciones y para add remove el evento CLR. Normalmente, add y remove se dejan como un valor predeterminado implícito que usa la sintaxis de eventos específica del lenguaje adecuada para agregar y quitar controladores de ese evento. El mecanismo de conexión y respaldo de eventos enrutados es conceptualmente similar a cómo una propiedad de dependencia es una propiedad CLR que está copiada por la clase y registrada con el sistema DependencyProperty WPF de propiedades.

En el ejemplo siguiente se muestra la declaración de un evento enrutado personalizado, incluido el registro y la exposición del campo identificador y las implementaciones y Tap RoutedEvent para el evento add remove Tap CLR.

public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
    "Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple));

// Provide CLR accessors for the event
public event RoutedEventHandler Tap
{
        add { AddHandler(TapEvent, value); }
        remove { RemoveHandler(TapEvent, value); }
}
Public Shared ReadOnly TapEvent As RoutedEvent = EventManager.RegisterRoutedEvent("Tap", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(MyButtonSimple))

' Provide CLR accessors for the event
Public Custom Event Tap As RoutedEventHandler
    AddHandler(ByVal value As RoutedEventHandler)
        Me.AddHandler(TapEvent, value)
    End AddHandler

    RemoveHandler(ByVal value As RoutedEventHandler)
        Me.RemoveHandler(TapEvent, value)
    End RemoveHandler

    RaiseEvent(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Me.RaiseEvent(e)
    End RaiseEvent
End Event

Controladores de eventos enrutados y XAML

Para agregar un controlador para un evento mediante XAML, declare el nombre del evento como un atributo en el elemento que actúa como agente de escucha de eventos. El valor del atributo es el nombre de su método de controlador implementado, que debe existir en la clase parcial del archivo de código subyacente.

<Button Click="b1SetColor">button</Button>

La sintaxis para agregar controladores de eventos CLR estándar es la misma para agregar controladores de eventos enrutados, ya que realmente se agregan controladores al contenedor de eventos CLR, que tiene una implementación de eventos enrutados XAML debajo. Para obtener más información sobre cómo agregar controladores de eventos en XAML , vea XAML en WPF.

Estrategias de enrutamiento

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

  • Propagación: se invocan los controladores de eventos en el origen del evento. Después, el evento enrutado va pasando por los elementos primarios sucesivos hasta alcanzar la raíz del árbol de elementos. La mayoría de los eventos enrutados usan la estrategia del enrutamiento de propagación. Los eventos con enrutamiento de propagación generalmente se usan para informar sobre cambios de entrada o de estado procedentes de controles distintos u otros elementos de la interfaz de usuario.

  • Directo: solo el propio elemento de origen tiene la oportunidad de invocar controladores como respuesta. Esto es análogo al "enrutamiento" que Windows Forms usa para los eventos. Sin embargo, a diferencia de un evento CLR estándar, los eventos enrutados directos admiten el control de clases (el control de clases se explica en una próxima sección) y los pueden usar EventSetter y EventTrigger .

  • Tunelización: inicialmente, se invocan los controladores de eventos en la raíz del árbol de elementos. Después, el evento enrutado viaja a través de los elementos secundarios sucesivos a lo largo de la ruta, hacia el elemento de nodo que es el origen del evento enrutado (el elemento que ha desencadenado el evento enrutado). Los eventos con enrutamiento de tunelización se suelen usar o controlar como parte de la composición de un control, de forma que los eventos de las partes compuestas se puedan suprimir o reemplazar deliberadamente por eventos que son específicos del control completo. Los eventos de entrada proporcionados en WPF se suelen implementar como un par de tunelización-propagación. Los eventos de tunelización también se conocen a veces como eventos de vista previa, debido a una convención de nomenclatura que se usa para los pares.

¿Por qué usar eventos enrutados?

Como desarrollador de aplicaciones, no siempre necesita saber ni preocuparse de si el evento que está controlando se implementa como un evento enrutado. Los eventos enrutados tienen un comportamiento especial, pero ese comportamiento es prácticamente invisible si está controlando un evento en el elemento donde se desencadena.

Los eventos enrutados demuestran su eficacia cuando se usa cualquiera de los escenarios sugeridos: definir los controladores comunes en una raíz común, componer un control personalizado o definir una clase de controles personalizada.

Los agentes de escucha y los orígenes de los eventos enrutados no necesitan compartir un evento común en su jerarquía. Cualquier UIElement o puede ser un agente de escucha de eventos para cualquier evento ContentElement enrutado. Por lo tanto, puede usar el conjunto completo de eventos enrutados disponibles en todo el conjunto de API de trabajo como una "interfaz" conceptual mediante la cual elementos dispares de la aplicación pueden intercambiar información de eventos. Este concepto de "interfaz" para los eventos enrutados es especialmente aplicable a los eventos de entrada.

Los eventos enrutados también se pueden usar para comunicar datos a través del árbol de elementos, porque los datos de evento para cada evento se perpetúan en cada elemento de la ruta. Un elemento podría cambiar algo en los datos del evento, y ese cambio estaría disponible para el elemento siguiente de la ruta.

Aparte del aspecto de enrutamiento, hay otras dos razones por las que un evento determinado podría implementarse como un evento enrutado en lugar de como un WPF evento CLR estándar. Si está implementando sus propios eventos, también podría considerar estos principios:

  • Algunas características de aplicación de estilos y de aplicación de estilos, como y requieren que el evento al que se hace WPF referencia sea un evento EventSetter EventTrigger enrutado. Este es el escenario del identificador de eventos mencionado anteriormente.

  • Los eventos enrutados admiten un mecanismo de control de clases en el que la clase puede especificar métodos estáticos que tienen la oportunidad de controlar eventos enrutados antes de que cualquier controlador de instancias registrado tenga acceso a ellos. Esto es muy útil en el diseño de controles, porque una clase puede exigir comportamientos de clase orientados a eventos que no se puedan suprimir accidentalmente controlando un evento en una instancia.

Cada una de las consideraciones anteriores se explica en una sección independiente de este tema.

Agregar e implementar un controlador de eventos para un evento enrutado

Para agregar un controlador de eventos en XAML, simplemente agregue el nombre del evento a un elemento como un atributo y establezca el valor del atributo como el nombre del controlador de eventos que implementa un delegado adecuado, como en el ejemplo siguiente.

<Button Click="b1SetColor">button</Button>

b1SetColor es el nombre del controlador implementado que contiene el código que controla el Click evento. b1SetColor debe tener la misma firma que el RoutedEventHandler delegado , que es el delegado del controlador de eventos para el Click evento. El primer parámetro de todos los delegados de controlador de eventos enrutados especifica el elemento al que se agrega el controlador de eventos y el segundo parámetro especifica los datos para el evento.

void b1SetColor(object sender, RoutedEventArgs args)
{
  //logic to handle the Click event
}
Private Sub b1SetColor(ByVal sender As Object, ByVal args As RoutedEventArgs)
  'logic to handle the Click event
End Sub

RoutedEventHandler es el delegado básico del controlador de eventos enrutados. Para los eventos enrutados especializados para ciertos controles o escenarios, los delegados que deben usarse para los controladores de eventos enrutados también podrían volverse más especializados, de forma que puedan transmitir datos de evento especializados. Por ejemplo, en un escenario de entrada común, puede controlar un DragEnter evento enrutado. El controlador debe implementar el DragEventHandler delegado. Mediante el uso del delegado más específico, puede procesar en el controlador y leer la propiedad , que contiene la carga del DragEventArgs Data Portapapeles de la operación de arrastre.

Para obtener un ejemplo completo de cómo agregar un controlador de eventos a un elemento mediante XAML, vea Cómo: Controlar un evento enrutado.

Resulta sencillo agregar un controlador para un evento enrutado en una aplicación que se crea en el código. Los controladores de eventos enrutados siempre se pueden agregar a través de un método auxiliar (que es el mismo método al que llama el AddHandler respaldo existente para add ). Sin embargo, los eventos enrutados existentes suelen tener implementaciones de respaldo de y lógica que permiten agregar los controladores de eventos enrutados mediante una sintaxis de eventos específica del lenguaje, que es una sintaxis más intuitiva que el método WPF add remove auxiliar. A continuación se muestra un ejemplo de uso del método del asistente:

void MakeButton()
 {
     Button b2 = new Button();
     b2.AddHandler(Button.ClickEvent, new RoutedEventHandler(Onb2Click));
 }
 void Onb2Click(object sender, RoutedEventArgs e)
 {
     //logic to handle the Click event
 }
Private Sub MakeButton()
     Dim b2 As New Button()
     b2.AddHandler(Button.ClickEvent, New RoutedEventHandler(AddressOf Onb2Click))
End Sub
 Private Sub Onb2Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
     'logic to handle the Click event     
 End Sub

En el ejemplo siguiente se muestra la sintaxis del operador de C# (Visual Basic sintaxis de operador ligeramente diferente debido a su control de la desreferenciación):

void MakeButton2()
{
  Button b2 = new Button();
  b2.Click += new RoutedEventHandler(Onb2Click2);
}
void Onb2Click2(object sender, RoutedEventArgs e)
{
  //logic to handle the Click event
}
Private Sub MakeButton2()
  Dim b2 As New Button()
  AddHandler b2.Click, AddressOf Onb2Click2
End Sub
Private Sub Onb2Click2(ByVal sender As Object, ByVal e As RoutedEventArgs)
  'logic to handle the Click event     
End Sub

Para obtener un ejemplo de cómo agregar un controlador de eventos en el código, vea Agregar un controlador de eventos mediante código.

Si usa Visual Basic, también puede usar la palabra clave para agregar controladores Handles como parte de las declaraciones de controlador. Para más información, vea Control de eventos en Visual Basic y WPF.

El concepto de controlado

Todos los eventos enrutados comparten una clase base de datos de eventos común, RoutedEventArgs . RoutedEventArgs define la Handled propiedad , que toma un valor booleano. El propósito de la propiedad es permitir que cualquier controlador de eventos a lo largo de la ruta marque el evento enrutado como manipulado, estableciendo el Handled valor de en Handled true . Una vez procesados por el controlador de un elemento a lo largo de la ruta, se informa de nuevo sobre los datos de evento compartidos a cada agente de escucha a lo largo de la ruta.

El valor de afecta a cómo se notifica o procesa un evento Handled enrutado a medida que se desplaza más a lo largo de la ruta. Si está en los datos de evento de un evento enrutado, los controladores que escuchan ese evento enrutado en otros elementos generalmente ya no se invocan para esa instancia Handled true de evento concreta. Esto se cumple tanto para los controladores adjuntos en XAML como para los controladores agregados mediante sintaxis de adjuntar controladores de eventos específicas del lenguaje como += o Handles. En los escenarios de controlador más comunes, marcar un evento como se controla estableciendo en "detendrá" el enrutamiento para una ruta de tunelización o una ruta de propagación, y también para cualquier evento que un controlador de clase controle en un punto de la Handled true ruta.

Sin embargo, hay un mecanismo "handledEventsToo" por el que los agentes de escucha todavía pueden ejecutar controladores en respuesta a eventos enrutados en los que se encuentra en los Handled true datos del evento. Es decir, la ruta de eventos no se detiene realmente al marcar los datos de evento como controlados. Solo puede usar el mecanismo handledEventsToo en el código o en EventSetter :

Además del comportamiento que el estado produce en los eventos enrutados, el concepto de tiene implicaciones sobre cómo debe diseñar la aplicación y escribir el código del Handled Handled controlador de eventos. Puede conceptualizar como Handled un protocolo simple que se expone mediante eventos enrutados. La forma exacta de usar este protocolo es su función, pero el diseño conceptual de cómo se pretende usar el valor de es el Handled siguiente:

  • Si un evento enrutado está marcado como controlado, no es necesario que los demás elementos a lo largo de esa ruta lo controlen de nuevo.

  • Si un evento enrutado no está marcado como manipulado, otros agentes de escucha que estaban anteriormente a lo largo de la ruta han elegido no registrar un controlador o los controladores registrados optaron por no manipular los datos del evento y establecer en Handled true . (O bien, por supuesto, es posible que el agente de escucha actual sea el primer punto de la ruta). Los controladores del agente de escucha actual ahora tienen tres posibles cursos de acción:

    • No realizar ninguna acción; el evento sigue estando sin controlar y se enruta al agente de escucha siguiente.

    • Ejecutar código en respuesta al evento, pero tomar la determinación de que la acción realizada no ha sido lo suficientemente sustancial como para marcar el evento como controlado. El evento se enruta al agente de escucha siguiente.

    • Ejecutar código en respuesta al evento. Marcar el evento como controlado en los datos de evento pasados al controlador, porque la acción realizada se ha considerado lo suficientemente sustancial como para marcarlo como controlado. El evento todavía se enruta al siguiente agente de escucha, pero con en sus datos de evento, por lo que solo los agentes de escucha tienen la oportunidad de Handled = true invocar handledEventsToo más controladores.

Este diseño conceptual se refuerza con el comportamiento de enrutamiento mencionado anteriormente: es más difícil (aunque todavía es posible en código o estilos) adjuntar controladores para eventos enrutados que se invocan incluso si un controlador anterior a lo largo de la ruta ya ha establecido Handled en true .

Para obtener más información sobre , control de clases de eventos enrutados y recomendaciones sobre cuándo es adecuado marcar un evento enrutado como , vea Marcar eventos enrutados como manipulados y Control de Handled Handled clases.

En las aplicaciones, es bastante habitual controlar un evento enrutado de propagación solamente en el objeto que lo ha desencadenado, y no preocuparse en absoluto por las características de enrutado del evento. Pero es una buena práctica marcar el evento enrutado como controlado en los datos de evento para evitar efectos secundarios imprevistos en caso de que un elemento situado más arriba en el árbol de elementos también tenga un controlador asociado para ese mismo evento enrutado.

Controladores de clase

Si va a definir una clase que deriva de alguna manera de , también puede definir y adjuntar un controlador de clases para un evento enrutado que sea un miembro de evento declarado o heredado de DependencyObject la clase. Los controladores de clase se invocan antes que cualquier controlador de agente de escucha de instancia que esté asociado a una instancia de esa clase, cada vez que un evento enrutado alcanza una instancia de elemento en su ruta.

Algunos controles de WPF tienen el control de clase inherente para ciertos eventos enrutados. Esto podría dar la impresión de que el evento enrutado nunca se genera, pero en realidad está sujeto al control de clase y sus controladores de instancia todavía pueden controlar el evento enrutado si emplea ciertas técnicas. Además, muchas clases y controles base exponen métodos virtuales que se pueden usar para invalidar el comportamiento del control de clase. Para más información sobre cómo evitar el control de clase no deseado y cómo definir su propio control de clase en una clase personalizada, vea Marcar eventos enrutados como controlados y control de clases.

Evento adjuntos en WPF

El lenguaje XAML también define un tipo especial de evento denominado evento adjunto. Un evento adjunto permite agregar un controlador para un evento determinado a un elemento arbitrario. No es necesario que el elemento que controla el evento defina o herede el evento adjunto, y ni el objeto que genera potencialmente el evento ni la instancia que controla el destino deben definir o ser "propietarios" de ese evento como miembro de clase.

El sistema de entrada de WPF emplea mucho los eventos adjuntos. Pero casi todos estos eventos adjuntos se reenvían a través de elementos base. Los eventos de entrada aparecen como eventos enrutados no adjuntos equivalentes que son miembros de la clase de elemento base. Por ejemplo, el evento adjunto subyacente se puede controlar más fácilmente en cualquier elemento dado mediante el uso de en , en lugar de tratar con la sintaxis de eventos Mouse.MouseDown UIElement MouseDown UIElement adjuntos en XAML o código.

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

Nombres de evento completos en XAML

Otro uso de una sintaxis similar a la sintaxis de eventos adjuntos nombreDeTipo.nombreDeEvento pero que no es en sentido estricto un uso de eventos adjuntos se produce al adjuntar controladores para eventos enrutados que son desencadenados por elementos secundarios. Los controladores se adjuntan a un elemento primario común, para aprovecharse del enrutamiento de eventos, aunque el evento enrutado pertinente no sea miembro del elemento primario común. Considere este ejemplo de nuevo:

<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
  <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
    <Button Name="YesButton" Width="Auto" >Yes</Button>
    <Button Name="NoButton" Width="Auto" >No</Button>
    <Button Name="CancelButton" Width="Auto" >Cancel</Button>
  </StackPanel>
</Border>

Aquí, el agente de escucha del elemento primario donde se agrega el controlador es StackPanel . Sin embargo, está agregando un controlador para un evento enrutado que se declaró y que la clase ( en realidad, pero disponible para a través de Button ButtonBase la Button herencia). Button "posee" el evento, pero el sistema de eventos enrutados permite que los controladores de cualquier evento enrutado se asocie a cualquier agente de escucha de instancia o que de otro modo pueda asociar agentes de escucha para un evento de UIElement ContentElement Common Language Runtime (CLR). El espacio de nombres xmlns predeterminado para estos nombres de atributo de evento calificados suele ser el espacio de nombres xmlns de WPF predeterminado, pero también se pueden especificar espacios de nombres con prefijos para los eventos enrutados personalizados. Para más información sobre xmlns, vea Espacios de nombres y asignación de espacios de nombres XAML para WPF.

Eventos de entrada de WPF

En la plataforma WPF, con frecuencia se emplean los eventos enrutados como eventos de entrada. En WPF, a los nombres de los eventos enrutados con tunelización se les antepone la palabra "Preview" por convención. Los eventos de entrada suelen presentarse en parejas, donde uno es el evento de propagación y el otro es el evento de tunelización. Por ejemplo, el evento y el evento tienen la misma firma, siendo el primero el evento de entrada de propagación y el segundo el evento de KeyDown PreviewKeyDown entrada de tunelización. En ocasiones, los eventos de entrada solo tienen una versión de propagación o quizás solo una versión enrutada directa. En la documentación, los temas sobre eventos enrutados contienen referencias cruzadas a los temas relativos a los eventos enrutados similares con estrategias de enrutamiento alternativas, si existen dichos eventos enrutados, y las secciones de las páginas de referencia administradas clarifican la estrategia de enrutamiento de cada evento enrutado.

Los eventos de entrada de WPF que se presentan en parejas se implementan de forma que una única acción del usuario desde la entrada, como presionar un botón del mouse, desencadenará los dos eventos enrutados de la pareja secuencialmente. En primer lugar, se desencadena el evento de tunelización, que viaja por su ruta. Después se desencadena el evento de propagación y este viaja por su ruta. Los dos eventos comparten literalmente la misma instancia de datos de evento, porque la llamada al método en la clase de implementación que genera el evento de propagación escucha los datos del evento de tunelización y los reutiliza en el nuevo evento que se RaiseEvent genera. Los agentes de escucha con controladores para el evento de tunelización tienen la primera oportunidad de marcar el evento enrutado como controlado (en primer lugar los controladores de clase y después los controladores de instancia). Si un elemento a lo largo de la ruta de tunelización ha marcado el evento enrutado como controlado, los datos del evento ya controlado se envían para el evento de propagación y no se invocarán los controladores adjuntos típicos para los eventos de entrada de propagación equivalentes. Externamente dará la impresión de que el evento de propagación controlado ni siquiera se ha desencadenado. Este comportamiento de control es útil para la composición de controles, donde podría ser conveniente que fuera el control final y no sus partes compuestas el que informara de todos los eventos de entrada basados en pruebas de posicionamiento o de los eventos de entrada basados en el foco. El elemento del control final está más próximo a la raíz en la composición y, por tanto, tiene la oportunidad de controlar desde la clase el evento de tunelización en primer lugar y posiblemente "reemplazar" dicho evento enrutado por un evento más específico del control, como parte del código que respalda la clase del control.

Para ilustrar cómo funciona el procesamiento de eventos de entrada, observe el ejemplo de evento de entrada siguiente. En la siguiente ilustración de árbol, leaf element #2 es el origen de un PreviewMouseDown y, a continuación, un MouseDown evento :

Diagrama de enrutamiento de eventos

El orden de procesamiento de los eventos es el siguiente:

  1. PreviewMouseDown (túnel) en el elemento raíz.

  2. PreviewMouseDown (túnel) en el elemento intermedio n.º 1.

  3. PreviewMouseDown (túnel) en el elemento de origen n.º 2.

  4. MouseDown (propagación) en el elemento de origen n.º 2.

  5. MouseDown (propagación) en el elemento intermedio n.º 1.

  6. MouseDown (propagación) en el elemento raíz.

Un delegado de controlador de eventos enrutados proporciona referencias a dos objetos: el objeto que ha desencadenado el evento y el objeto en el que se ha invocado el controlador. El objeto en el que se ha invocado el controlador es el objeto sobre el que informa el parámetro sender. La propiedad notifica el objeto donde se presentó el evento por primera vez Source en los datos del evento. El mismo objeto todavía puede generar y controlar un evento enrutado, en cuyo caso y son idénticos (es el caso de los pasos 3 y 4 de la lista de ejemplos de procesamiento sender Source de eventos).

Debido a la tunelización y la propagación, los elementos primarios reciben eventos de entrada donde Source es uno de sus elementos secundarios. Cuando es importante saber cuál es el elemento de origen, puede identificar el elemento de origen accediendo a la Source propiedad .

Normalmente, una vez que el evento de entrada está Handled marcado, no se invocan más controladores. Lo habitual es marcar los eventos de entrada como controlados en cuanto se invoca un controlador que se ocupa del control lógico específico de la aplicación relacionado con el significado del evento de entrada.

La excepción a esta instrucción general sobre el estado es que los controladores de eventos de entrada que están registrados para omitir deliberadamente el estado de los datos del evento se seguirán invocando a lo Handled Handled largo de cualquier ruta. Para más información, vea Eventos de vista previa o Marcar eventos enrutados como controlados y control de clases.

El modelo de datos de evento compartido entre los eventos de tunelización y de propagación, y el desencadenamiento secuencial primero de los eventos de tunelización y después de los de propagación, no es un concepto que se cumpla de forma general para todos los eventos enrutados. Ese comportamiento se implementa específicamente según el modo en que los dispositivos de entrada de WPF deciden generar y conectar los pares de eventos de entrada. Implementar sus propios eventos de entrada es un escenario avanzado, pero también podría decidir seguir ese modelo para sus propios eventos de entrada.

Algunas clases eligen controlar ciertos eventos de entrada mediante clases, normalmente con la intención de volver a definir lo que significa un determinado evento de entrada controlado por el usuario dentro de ese control y de desencadenar un nuevo evento. Para más información, vea Marcar eventos enrutados como controlados y control de clases.

Para más información sobre la entrada y cómo interactúa con los eventos en escenarios de aplicación típicos, vea Información general sobre acciones del usuario.

EventSetters y EventTriggers

En los estilos, puede incluir alguna sintaxis de control de eventos declarada previamente XAML en el marcado mediante EventSetter . Cuando se aplica el estilo, el controlador al que se hace referencia se agrega a la instancia que recibe el estilo. Puede declarar un solo EventSetter para un evento enrutado. A continuación se muestra un ejemplo. Tenga en cuenta que el método b1SetColor al que se hace referencia aquí está en un archivo de código subyacente.

<StackPanel
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.EventOvw2"
  Name="dpanel2"
  Initialized="PrimeHandledToo"
>
  <StackPanel.Resources>
    <Style TargetType="{x:Type Button}">
      <EventSetter Event="Click" Handler="b1SetColor"/>
    </Style>
  </StackPanel.Resources>
  <Button>Click me</Button>
  <Button Name="ThisButton" Click="HandleThis">
    Raise event, handle it, use handled=true handler to get it anyway.
  </Button>
</StackPanel>

La ventaja que se ha obtenido aquí es que es probable que el estilo contenga una gran cantidad de otra información que podría aplicarse a cualquier botón de la aplicación y que formar parte de ese estilo promueve la reutilización del código incluso en el nivel de EventSetter marcado. Además, abstrae los nombres de método para los controladores un paso más lejos del marcado general de la aplicación EventSetter y la página.

Otra sintaxis especializada que combina las características de animación y eventos enrutados WPF de es EventTrigger . Al igual que EventSetter con , solo se pueden usar eventos enrutados para EventTrigger . Normalmente, se declara como parte de un estilo, pero también se puede declarar en elementos de nivel de página como parte de la colección EventTrigger EventTrigger o en Triggers ControlTemplate . Permite especificar un objeto que se ejecuta cada vez que un evento enrutado alcanza un elemento de su ruta que EventTrigger Storyboard declara para ese EventTrigger evento. La ventaja de un en lugar de controlar el evento y hacer que se inicie un guión gráfico existente es que proporciona un mejor control sobre el guión gráfico y su comportamiento EventTrigger EventTrigger en tiempo de ejecución. Para más información, vea Cómo: Utilizar desencadenadores de eventos para controlar un guión gráfico después de su inicio.

Más información sobre los eventos enrutados

En este tema se explican principalmente los eventos enrutados desde la perspectiva de describir los conceptos básicos y proporcionar orientación sobre cómo y cuándo responder a los eventos enrutados que ya existen en los distintos elementos y controles base. Pero puede crear sus propios eventos enrutados en su clase personalizada junto con toda la compatibilidad necesaria, como clases y delegados de datos de evento especializados. El propietario del evento enrutado puede ser cualquier clase, pero los eventos enrutados los deben generar y controlar las clases derivadas o para UIElement ContentElement que sean útiles. Para más información sobre los eventos personalizados, vea Crear un evento enrutado personalizado.

Consulte también