Introducción a eventos y eventos enrutados

Applies to Windows and Windows Phone

Aquí describimos el concepto de programación de eventos en una aplicación de Windows en tiempo de ejecución cuando se usa C#, Visual Basic o extensiones de componentes de Visual C++ (C++/CX) como lenguaje de programación y XAML para la definición de la interfaz de usuario. Puedes asignar controladores para eventos como parte de las declaraciones de los elementos de la interfaz de usuario en XAML, o puedes agregar los controladores en el código. Windows en tiempo de ejecución admite eventos enrutados, que implica que ciertos eventos de entrada y eventos de datos pueden ser administrados por otros objetos distintos del objeto que originó el evento. Los eventos enrutados son útiles cuando tienes que definir plantillas de control o usar contenedores de páginas o de diseño.

Eventos como concepto de programación

En general, los conceptos de eventos para programar una aplicación de Windows en tiempo de ejecución son parecidos al modelo de eventos de los lenguajes de programación más populares. Si ya sabes cómo trabajar con eventos de Microsoft .NET o C++, ya cuentas con ventaja. Pero no tienes por qué saber tanto sobre conceptos del modelo de eventos para poder realizar algunas tareas básicas, como adjuntar controladores.

Cuando usas C#, Visual Basic o C++/CX como lenguaje de programación, la interfaz de usuario se define en el marcado (XAML). En la sintaxis del marcado XAML, algunos de los principios para conectar eventos entre los elementos de marcado y las entidades de código en tiempo de ejecución son similares a otras tecnologías web como ASP.NET o HTML5.

Nota  El código que proporciona la lógica en tiempo de ejecución para una interfaz de usuario definida por XAML se suele denominar código subyacente o archivo de código subyacente. En las vistas de la solución de Microsoft Visual Studio, esta relación se muestra gráficamente, con el archivo de código subyacente como archivo dependiente y anidado frente a la página XAML a la que hace referencia.

Button.Click: introducción a los eventos y a XAML

Una de las tareas de programación más comunes de una aplicación de Windows en tiempo de ejecución es capturar la entrada del usuario en la interfaz de usuario. Por ejemplo, la interfaz de usuario podría tener un botón en el que el usuario deba hacer clic para enviar información o cambiar el estado.

La interfaz de usuario de la aplicación de Windows en tiempo de ejecución se define al generar el código XAML. Este XAML suele ser el resultado de una superficie de diseño en Visual Studio. El código XAML también se puede escribir en un editor de texto sin formato o en un editor XAML de terceros. Mientras generas ese código XAML, puedes conectar controladores de eventos para elementos individuales de la interfaz de usuario y, al mismo tiempo, definir todos los demás atributos XAML que establecen los valores de propiedad de ese elemento de la interfaz de usuario.

Para conectar eventos en XAML, tienes que especificar el nombre de cadena del método del controlador que ya has definido o que vas a definir más tarde en el código subyacente. Por ejemplo, este código XAML define un objeto Button con otras propiedades (x:Name, Content) asignadas como atributos, y conecta un controlador para el evento Click del botón, mediante una referencia al método showUpdatesButton_Click:


<Button x:Name="showUpdatesButton"
  Content="{Binding ShowUpdatesText}"
  Click="showUpdatesButton_Click"/>

Sugerencia   La conexión de eventos es un término de programación. Hace referencia al proceso o al código que se utilizan para indicar que las ocurrencias de un evento deben invocar a un método de controlador con nombre. En la mayoría de modelos de código procesales, la conexión de eventos es el código "AddHandler" implícito o explícito que da nombre tanto al evento como al método, y normalmente implica una instancia de objeto de destino. En XAML, el código "AddHandler" está implícito y la conexión de eventos consiste en su totalidad en utilizar el nombre de atributo de un elemento de objeto como nombre del evento y el valor de ese atributo como nombre del controlador.

Escribe el controlador real en el lenguaje de programación que estés usando para todo el código de la aplicación y el código subyacente. Con el atributo Click="showUpdatesButton_Click", creaste un contrato por el cual cuando se compila y se analiza el código XAML para marcado, tanto el proceso de compilación del marcado XAML de la acción de compilación del IDE como el proceso de análisis del XAML final cuando se carga la aplicación, pueden encontrar un método showUpdatesButton_Click dentro del código de la aplicación. showUpdatesButton_Click debe ser un método que implemente una firma de método compatible (basada en un delegado) para cualquier controlador del evento Click. Por ejemplo, este código define el controlador showUpdatesButton_Click.


private void showUpdatesButton_Click (object sender, RoutedEventArgs e) {
    Button b = sender as Button;
    //more logic to do here...
}

En este ejemplo, el método showUpdatesButton_Click se basa en el delegado RoutedEventHandler. Sabrás que este es el delegado que hay que usar porque verás el nombre de ese delegado en la sintaxis para el método Click en la página de referencia de MSDN.

Sugerencia  Visual Studio ofrece una manera cómoda de asignar nombre al controlador de eventos y definir el método del controlador mientras editas código XAML. Cuando proporciones el nombre de atributo del evento en el editor de texto XAML, espera un momento hasta que se muestre una lista de Microsoft IntelliSense. Si haces clic en <Nuevo controlador de eventos> en la lista, Microsoft Visual Studio sugerirá un nombre de método basado en el x:Name (o nombre de tipo) del elemento, el nombre del evento y un sufijo numérico. Entonces puedes hacer clic en el nombre de controlador de eventos seleccionado y hacer clic en Navegar al controlador de eventos. De esta manera irás directamente a la definición de controlador de eventos recién insertada, como se ve en la vista del editor de código del archivo de código subyacente para la página XAML. El controlador de eventos ya tiene la firma correcta, incluido el parámetro sender y la clase de datos de evento que el evento usa. Además, si ya existe un método de controlador con la firma correcta en tu código subyacente, aparecerá ese nombre de método en la lista desplegable con autocompletar, junto con la opción <Nuevo controlador de eventos>. También puedes presionar la tecla Tab como método abreviado en lugar de hacer clic en los elementos de la lista de IntelliSense.

Definición de un controlador de evento

En el caso de los objetos que son elementos de la interfaz de usuario y están declarados en XAML, el código de controlador de evento se define en la clase parcial que funciona como código subyacente de una página XAML. Los controladores de eventos son métodos que escribes como parte de la clase parcial que está asociada a tu código XAML. Estos controladores de eventos se basan en los delegados que un evento determinado usa. Los métodos de tu controlador de eventos pueden ser públicos o privados. El acceso privado funciona porque el controlador y la instancia que creó el código XAML se unen finalmente con la generación del código. La recomendación general es hacer que los métodos del controlador de eventos sean privados en la clase.

Nota  Los controladores de eventos de C++ no se definen en clases parciales, se declaran en el encabezado como miembro de clase privada. Las acciones de compilación de un proyecto C++ se encargan de generar código que admita el sistema de tipo XAML y el modelo de código subyacente para C++.

El parámetro sender y los datos del evento

El controlador que escribas para el evento puede acceder a dos valores que están disponibles como entrada para cada caso en el que se invoca el controlador. El primero de estos valores es sender, que es una referencia al objeto donde se adjunta el controlador. El parámetro sender se escribe como el tipo Object base. Una técnica común es convertir sender a un tipo más preciso. Esta técnica resulta útil si esperas comprobar o cambiar el estado en el objeto sender mismo. En función del diseño de tu aplicación, normalmente sabes que el tipo al que se convierte sender es seguro, según la ubicación donde se adjuntó el controlador u otros aspectos específicos del diseño.

El segundo valor son los datos del evento, que generalmente aparecen en las definiciones de sintaxis como el parámetro e. Puedes descubrir qué propiedades se encuentran disponibles para los datos del evento examinando el parámetro e del delegado que está asignado al evento específico que estás controlando y después mediante IntelliSense o el examinador de objetos de Visual Studio. También puedes usar la documentación de referencia de Windows en tiempo de ejecución.

Para algunos eventos, los valores de propiedad específicos de los datos del evento son tan importantes como saber que el evento ocurrió. Esto es especialmente cierto en los eventos de entrada. Para los eventos de puntero, podría ser importante la posición del puntero al producirse el evento. En el caso de los eventos de teclado, todas las posibles pulsaciones de tecla generan un evento KeyDown y KeyUp. Para determinar qué tecla presionó el usuario, debes acceder a KeyRoutedEventArgs que está a disposición del controlador de eventos. Para obtener más información sobre el control de eventos, consulta Responder a la entrada de teclado e Inicio rápido: punteros. Los eventos de entrada y los escenarios de entrada generalmente tienen consideraciones adicionales que no se tratan en este tema, como la captura del puntero de los eventos de puntero y las teclas modificadoras y los códigos de teclas de la plataforma para los eventos de teclado.

Controladores de eventos que usan el patrón async

En ocasiones, querrás utilizar las API que usan un patrón async en un controlador de eventos. Por ejemplo, podrías usar un Button en un AppBar para mostrar un selector de archivos e interactuar con él. Pero muchas de las API del selector de archivos son asincrónicas. Es necesario llamarlas en un ámbito al que se pueda aplicar await/async, y el compilador exigirá este comportamiento. Así que lo que puedes hacer es agregar la palabra clave async al controlador de eventos, de modo que este pase a ser async void. Ahora se permite al controlador de eventos realizar llamadas a las que se puede aplicar await/async.

Para obtener un ejemplo de controladores de evento de interacción del usuario con el patrón async, consulta el tema sobre el acceso a los archivos y selectores de archivos (que forma parte de la serie sobre cómo crear la primera aplicación de Windows en tiempo de ejecución con C# o Visual Basic). Consulta también Inicio rápido: llamar a API asincrónicas en C# o Visual Basic.

Agregar controladores de eventos en el código

XAML no es la única forma de asignar un controlador de evento a un objeto. Para agregar controladores de eventos a un objeto en particular en el código, incluidos los objetos que no pueden usarse en XAML, puedes usar la sintaxis específica del lenguaje para agregar controladores de eventos.

En C#, la sintaxis es usar el operador +=. El controlador se registra haciendo referencia al nombre del método del controlador del evento que se encuentra a la derecha del operador.

Si usas un código para agregar controladores de eventos a los objetos que aparecen en la interfaz de usuario en tiempo de ejecución, se recomienda agregar esos controladores en respuesta a una devolución de llamada o evento de vigencia del objeto, como Loaded o OnApplyTemplate, de manera que los controladores de eventos del objeto correspondiente estén listos para los eventos que inicie el usuario en tiempo de ejecución. En este ejemplo se muestra un esquema XAML de la estructura de página y se proporciona la sintaxis en lenguaje C# para agregar un controlador de eventos a un objeto.


<Grid x:Name="LayoutRoot" Loaded="LayoutRoot_Loaded">
  <StackPanel>
    <TextBlock Name="textBlock1">Put the pointer over this text</TextBlock>
...
  </StackPanel>
</Grid>


void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
    textBlock1.PointerEntered += textBlock1_PointerEntered;
    textBlock1.PointerExited += textBlock1_PointerExited;
}

Nota  Existe una sintaxis más detallada. En 2005, C# incorporó una característica llamada inferencia de delegado, que permite a un compilador inferir una nueva instancia de delegado y habilita la sintaxis anterior que es más simple. La sintaxis detallada es funcionalmente idéntica al ejemplo anterior, pero crea explícitamente una nueva instancia de delegado antes de registrarla y, por lo tanto, no aprovecha la inferencia de delegado. Esta sintaxis explícita es menos común, pero podrías verla en algunos ejemplos de código.


void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
    textBlock1.PointerEntered += new PointerEventHandler(textBlock1_PointerEntered);
    textBlock1.PointerExited += new MouseEventHandler(textBlock1_PointerExited);
}

Existen dos posibilidades para la sintaxis de Visual Basic. Una es cotejar la sintaxis de C# y adjuntar controladores directamente a las instancias. Esto requiere la palabra clave AddHandler y también el operador AddressOf que anula la referencia al nombre del método del controlador.

La otra opción de la sintaxis de Visual Basic es usar la palabra clave Handles en los controladores de eventos. Esta técnica es apropiada para casos en los que se espera que existan controladores en los objetos en tiempo de carga y que persistan durante la vigencia del objeto. Si usas Handles en un objeto que está definido en XAML, debes proporcionar un Name/x:Name. Este nombre se convierte en el calificador de instancia necesario para la parte Instance.Event de la sintaxis de Handles. En este caso, no necesitas un controlador de eventos basado en la vigencia del objeto para iniciar la conexión de otros controladores de eventos; las conexiones Handles se crean cuando compilas tu página XAML.


Private Sub textBlock1_PointerEntered(ByVal sender As Object, ByVal e As PointerRoutedEventArgs) Handles textBlock1.PointerEntered
'...
End Sub

Nota  Visual Studio y su superficie de diseño XAML generalmente promueven la técnica de control de instancias en lugar de la palabra clave Handles. Esto se debe a que establecer la conexión del controlador de eventos en XAML forma parte del flujo de trabajo del desarrollador y diseñador, y la técnica de la palabra clave Handles es incompatible con la conexión de los controladores de eventos en XAML:

En C++, también se usa la sintaxis +=, pero ten en cuenta las siguientes diferencias respecto al formato C# básico:

  • No existe inferencia de delegado, por lo que debes usar ref new para la instancia de delegado.
  • El constructor delegado tiene dos parámetros y requiere el objeto de destino como primer parámetro. Generalmente, especificas this.
  • El constructor delegado requiere la dirección del método como segundo parámetro para que el operador que anula la referencia de & preceda al nombre del método.

textBlock1->PointerEntered += 
ref new PointerEventHandler(this,&BlankPage::textBlock1_PointerExited);

Quitar controladores de eventos del código

Normalmente, no es necesario quitar controladores de eventos del código aunque se hayan agregado a él. El comportamiento de duración del objeto en la mayoría de los objetos de Windows en tiempo de ejecución, como páginas y controles, destruirá los objetos cuando se desconecten de la Window principal y su árbol visual, y también se destruirán las referencias delegadas. Para ello, .NET usa la recolección de elementos no utilizados y Windows en tiempo de ejecución con C++/CX usa referencias débiles de manera predeterminada.

En ocasiones excepcionales, querrás quitar los controladores de eventos de forma explícita. Estas son:

  • Controladores agregados para eventos estáticos, en los que no se puede usar la recolección de eventos no utilizados de manera convencional. Algunos ejemplos de eventos estáticos en la API de Windows en tiempo de ejecución son los eventos de las clases CompositionTarget y Clipboard.
  • Prueba el código donde quieres que la eliminación de controladores sea inmediata o el código donde quieres intercambiar controladores de eventos antiguos/nuevos para un evento en tiempo de ejecución.
  • La implementación de un descriptor de acceso remove personalizado.
  • Eventos estáticos personalizados.
  • Controladores para las navegaciones de la página.

FrameworkElement.Unloaded o Page.NavigatedFrom son desencadenadores de eventos posibles que tienen posiciones adecuadas en la administración de estado y la duración del objeto, de tal forma que puedes usarlos para quitar controladores para otros eventos.

Por ejemplo, puedes quitar un controlador de eventos denominado textBlock1_PointerEntered del objeto de destino textBlock1 con este código.


textBlock1.PointerEntered -= textBlock1_PointerEntered;

También puedes quitar controladores cuando el evento se haya agregado a través de un atributo XAML, lo que implica que el controlador se agregó en código generado. Esto resulta más sencillo si proporcionaste un valor de Name para el elemento al que se adjuntó el controlador, ya que proporciona una referencia a objeto para el código posterior; sin embargo, también podrías recorrer el árbol de objetos para buscar la referencia a objeto necesaria en los casos en los que el objeto no tenga un Name.

Si necesitas quitar un controlador de eventos en C++/CX, necesitarás un token de registro, que deberías haber recibido del valor devuelto del registro del controlador de eventos +=. Esto se debe a que el valor utilizado para el lado derecho de la anulación de registro de -= en la sintaxis C++/CX es el token y no el nombre del método. En C++/CX, no puedes quitar controladores que se agregaron como un atributo XAML porque el código generado en C++/CX no guarda un token.

Eventos enrutados

Windows en tiempo de ejecución con C#, Microsoft Visual Basic o C++/CX admite el concepto de evento enrutado para un conjunto de eventos que están presentes en la mayoría de los elementos de la interfaz de usuario. Estos eventos se usan en escenarios de entrada e interacción del usuario, y se implementan en la clase base UIElement. Esta es una lista de eventos de entrada que son eventos enrutados:

Un evento enrutado es un evento que posiblemente se pasa (se enruta) desde un objeto secundario a cada uno de sus objetos principales sucesivos en un árbol de objetos. La estructura XAML de tu interfaz de usuario se asemeja a este árbol, en el que la raíz es el elemento raíz en XAML. El verdadero árbol de objetos podría variar en cierta forma del anidamiento del elemento XAML, porque el primero no incluye características del lenguaje XAML, como las etiquetas de elementos de propiedad. Puedes considerar los eventos enrutados como una propagación desde el elemento de objeto XAML secundario que genera el evento hacia el elemento de objeto primario que los contiene. El evento y su evento de datos se pueden administrar en varios objetos junto con la ruta del evento. Si ningún elemento tiene controladores, la ruta probablemente siga avanzando hasta alcanzar el elemento raíz.

Si conoces las tecnologías web como Dynamic HTML (DHTML) o HTML5, quizás ya estés familiarizado con el concepto de evento de propagación.

Cuando un evento enrutado se propaga por su ruta de evento, todos los controladores de eventos adjuntos acceden a una instancia compartida de los datos del evento. Por lo tanto, si un controlador puede escribir cualquiera de los datos del evento, los cambios realizados en estos se pasarán al próximo controlador y puede que ya no representen los datos originales del evento. Cuando un evento tiene un comportamiento de evento enrutado, la documentación de referencia incluirá comentarios u otras anotaciones sobre el comportamiento enrutado.

La propiedad OriginalSource de RoutedEventArgs

Cuando un evento propaga una ruta de evento, sender ya no es el mismo objeto que generó el evento. En cambio, sender es el objeto donde se adjunta el controlador que se está invocando.

En algunos casos, sender no es el objeto que te interesa y, en cambio, quieres conocer otra información, por ejemplo, sobre cuál de los posibles elementos secundarios se encontraba el puntero al desencadenarse un evento de puntero o qué objeto de una interfaz de usuario más amplia tenía el foco cuando un usuario presionó una tecla. En estos casos, puedes usar el valor de la propiedad OriginalSource. En todos los puntos de la ruta, OriginalSource notifica el objeto original que generó el evento y no el objeto al que se adjuntó el controlador. Pero para los eventos de entrada UIElement, ese objeto original suele ser uno que no es inmediatamente visible en el XAML de definición de la interfaz de usuario de la página. En cambio, podría ser una parte con plantilla de un control. Por ejemplo, si el usuario mantiene el puntero sobre el borde de un Button, para la mayoría de los eventos de puntero OriginalSource es una parte de la plantilla Border en Template y no el Button propiamente dicho.

Sugerencia  La propagación de eventos de entrada es especialmente útil al crear un control con plantilla. En todos los controles que tienen una plantilla, su consumidor puede aplicar una nueva plantilla. Un consumidor que intenta recrear una plantilla de trabajo podría eliminar por accidente cierto código de control de eventos declarado en la plantilla predeterminada. Aún puedes proporcionar código de control de eventos en el nivel del control adjuntando controladores como parte de la invalidación OnApplyTemplate en la definición de la clase. Luego puedes capturar los eventos de entrada que se propagan en la raíz del control durante la creación de instancias.

La propiedad Handled

Varias clases de datos de evento de eventos enrutados específicos contienen una propiedad llamada Handled. Para ver ejemplos, consulta PointerRoutedEventArgs.Handled, KeyRoutedEventArgs.Handled, DragEventArgs.Handled. En todos los casos, Handled es una propiedad booleana configurable.

Establecer la propiedad Handled en true influye en el comportamiento del sistema de eventos. Si Handled es true, el enrutamiento se detiene para la mayoría de los controladores de eventos; el evento no continúa a lo largo de la ruta para notificar a otros controladores adjuntos de ese caso de evento en particular. De ti dependen el significado de la acción "controlar" en el contexto del evento y el modo en que la aplicación responde a ella. Básicamente, Handled es un protocolo simple que permite que el código de la aplicación declare que una instancia de un evento no necesita propagarse en ningún contenedor, ya que la lógica de la aplicación se encarga de realizar las acciones necesarias. Por otro lado, debes tener cuidado de no controlar eventos que quizás tengan que propagarse para que puedan tener lugar comportamientos de control o del sistema integrados. Por ejemplo, controlar eventos de bajo nivel en partes o elementos de un control de selección puede ser perjudicial. El control de selección podría estar buscando eventos de entrada para determinar si la selección debe cambiar.

No todos los eventos enrutados pueden cancelar una ruta de esta forma y lo sabrás porque no tendrán la propiedad Handled. Por ejemplo, GotFocus y LostFocus se propagan, pero siempre lo hacen siguiendo todo el recorrido hasta la raíz, y sus clases de datos de evento no tienen una propiedad Handled que pueda influir en ese comportamiento.

Controladores de eventos de entrada en controles

Algunos controles de Windows en tiempo de ejecución a veces usan el concepto Handled para los eventos de entrada internamente. Esto puede hacer que parezca que un evento de entrada nunca se produce, porque el código de usuario no puede controlarlo. Por ejemplo, la clase Button incluye una lógica que controla deliberadamente el evento de entrada general PointerPressed. Lo hace de esa manera porque los botones generan un evento Click que se inicia con una entrada de presión de puntero, y también con otros modos de entrada, como el control teclas como Entrar, que pueden invocar el botón cuando recibe el foco. Para el diseño de clase de Button, el evento de entrada sin procesar se controla conceptualmente y, en su lugar, los consumidores de la clase, como tu código de usuario, pueden interactuar con el evento Click relevante para el control. Los temas sobre las clases de control específicas en la referencia de la API de Windows en tiempo de ejecución a menudo advierten del comportamiento de control de eventos que la clase implementa. En algunos casos, puedes cambiar el comportamiento anulando los métodos OnEvent. Por ejemplo, puedes cambiar la forma en que tu clase derivada TextBox reacciona a la entrada de teclado anulando Control.OnKeyDown.

Registrar controladores para eventos enrutados previamente controlados

Anteriormente hemos dicho que establecer Handled en true impide que se invoque la mayoría de los controladores. Sin embargo, el método AddHandler ofrece una técnica con la que puedes adjuntar un controlador que se invoca siempre para la ruta, aunque otro controlador anterior de la ruta haya establecido Handled en true en los datos de evento compartidos. Esta técnica resulta útil si un control que usas ha controlado el evento en su composición interna o para lógica específica del control, pero aún quieres responder a él desde una instancia del control o desde la interfaz de usuario de la aplicación. Sin embargo, esta técnica se debe usar con precaución porque puede contradecir el propósito de Handled y, posiblemente, interrumpir las interacciones previstas para el control.

Solo los eventos enrutados que tienen un identificador de evento enrutado correspondiente pueden usar la técnica de control de eventos AddHandler, ya que el identificador es una entrada obligatoria del método AddHandler. Consulta la documentación de referencia de AddHandler para obtener una lista de los eventos que tienen identificadores de evento enrutado disponibles. La mayor parte de esta lista coincide con la lista de eventos enrutados que te mostramos anteriormente. La excepción es que los dos últimos eventos de la lista, GotFocus y LostFocus, no tienen un identificador de evento enrutado, de modo que no puedes usar AddHandler para ellos.

Eventos enrutados fuera del árbol visual

Ciertos objetos participan en una relación con el árbol visual principal que conceptualmente es similar a tener una superposición sobre los elementos visuales principales. Estos objetos no forman parte de las relaciones habituales entre elementos principales y secundarios que conectan todos los elementos del árbol con la raíz visual. Este es el caso para cualquier Popup o ToolTip que se muestre. Si deseas controlar los eventos enrutados de un Popup o ToolTip, debes colocar los controladores en elementos específicos de la interfaz de usuario que estén dentro de Popup o ToolTip, y no los elementos Popup o ToolTip en sí mismos. No dependas del enrutamiento que se realiza en el interior de la composición que se lleva a cabo para el contenido de Popup o ToolTip. Esto se debe a que el enrutamiento de eventos enrutados solo funciona a lo largo del árbol visual principal. No se considera que Popup o ToolTip sean elementos principales de los elementos de la interfaz de usuario subsidiaria y nunca reciben el evento enrutado, aunque traten de usar algo similar al fondo predeterminado de Popup como área de captura para los eventos de entrada.

Prueba de acceso y eventos de entrada

La determinación de si un elemento es visible para la entrada táctil, la entrada de ratón o la entrada de lápiz y de dónde está visible se denomina prueba de acceso. En el caso de las acciones táctiles y también de los eventos de manipulación o específicos de la interacción que son consecuencia de una acción táctil, un elemento debe ser visible en la prueba de acceso para poder ser origen de eventos y generar el evento que está asociado a la acción. De lo contrario, la acción pasa a través del elemento a cualquier elemento subyacente o elemento principal del árbol visual que pueda interaccionar con esos datos. Hay varios factores que afectan a la prueba de acceso, pero puedes determinar si un elemento específico puede generar eventos de entrada comprobando la propiedad IsHitTestVisible. Esta propiedad devuelve true solo si el elemento cumple con los siguientes criterios:

  • El valor de la propiedad Visibility del elemento es Visible.
  • El valor de la propiedad Background o Fill del elemento no es null. Un valor null de Brush provoca transparencia e invisibilidad en la prueba de posicionamiento. (Para que un elemento sea transparente pero se pueda someter a la prueba de posicionamiento, usa un pincel Transparent en lugar de null).

    Nota  Background y Fill no se definen con UIElement; en su lugar, se definen mediante diversas clases derivadas como Control y Shape. Sin embargo, las implicaciones de los pinceles que uses para las propiedades de primer plano y segundo plano son las mismas para la prueba de acceso y los eventos de entrada, independientemente de qué subclase implemente las propiedades.

  • Si el elemento es un control, el valor de la propiedad IsEnabled debe ser true.
  • El elemento debe tener dimensiones reales en el diseño. Un elemento con valores 0 en ActualHeight y ActualWidth no generarán eventos de entrada.

Algunos controles tienen reglas especiales para la prueba de acceso. Por ejemplo, TextBlock no tiene ninguna propiedad Background pero se puede someter a la prueba de acceso en toda la región de sus dimensiones. Los controles Image y MediaElement se pueden someter a la prueba de acceso en las dimensiones definidas de su rectángulo, independientemente del contenido transparente como el canal alfa en el archivo de origen multimedia que se está mostrando. Los controles WebView tienen un comportamiento especial en la prueba de acceso porque el HTML hospedado puede controlar la entrada y generar eventos de script.

La mayoría de las clases Panel y Border no se pueden someter a la prueba de posicionamiento en su propio segundo plano, aunque pueden controlar los eventos de entrada de usuario que se enrutan desde los elementos que contienen.

Puedes determinar qué elementos están ubicados en la misma posición que un evento de entrada de usuario, independientemente de si se puede realizar la prueba de acceso en los elementos o no. Para ello, llama al método FindElementsInHostCoordinates. Tal como indica el nombre, este método busca los elementos en una ubicación relativa a un elemento host especificado. Pero las transformaciones aplicadas y los cambios de diseño pueden ajustar el sistema de coordenadas relativo de un elemento y, por tanto, afectar a los elementos que se encuentran en una ubicación determinada.

Comandos

Algunos elementos de la interfaz de usuario admiten comandos. Los comandos usan eventos enrutados relacionados con la entrada en su implementación subyacente y permiten procesar la entrada de la interfaz de usuario relacionada (una acción de puntero determinada o una tecla aceleradora específica) mediante la invocación de un único controlador de comandos. Si hay comandos disponibles para un elemento de la interfaz de usuario, considera la posibilidad de usar las API de comandos en lugar de eventos de entrada discretos. Las referencias Binding se suelen usar en propiedades de una clase que define el modelo de vista de los datos. Las propiedades contienen comandos con nombre que implementan el patrón de comandos ICommand específico del lenguaje. Para más información, consulta ButtonBase.Command.

Eventos personalizados en Windows en tiempo de ejecución

A la hora de definir eventos personalizados, el modo en que se agrega el evento y el significado que ello tiene para el diseño de la clase depende en gran medida del lenguaje de programación que utilices.

  • En C# y Visual Basic, defines un evento CLR. Puedes usar el patrón de eventos de .NET estándar, siempre y cuando no uses descriptores de acceso personalizado (add/remove). Sugerencias adicionales:
  • Para C++/CX, consulta Eventos (C++/CX).
    • Usa referencias con nombre incluso en tus propios usos de eventos personalizados. No utilices lambda para eventos personalizados, ya que puede crear una referencia circular.

No puedes declarar un evento enrutado personalizado para Windows en tiempo de ejecución; los eventos enrutados se limitan al conjunto procedente de Windows en tiempo de ejecución.

La definición de un evento personalizado suele realizarse como parte del ejercicio de definir un control personalizado. Un patrón común consiste en tener una propiedad de dependencia con una devolución de llamada modificada por propiedades y definir un evento personalizado generado por la devolución de llamada modificada por propiedades en algunos casos o siempre. Los usuarios del control no tienen acceso a la devolución de llamada modificada por propiedades que has definido pero sí disponen de un evento de notificación. Para obtener más información, consulta Propiedades de dependencia personalizadas.

Temas relacionados

Introducción a XAML
Inicio rápido: entrada táctil
Respuesta a la entrada de teclado
Eventos y funciones delegadas de .NET
Creación de componentes de Windows en tiempo de ejecución
AddHandler

 

 

Mostrar:
© 2014 Microsoft