El problema:

Una de las principales ventajas que aporta las aplicaciones UWP es que la misma aplicación la podemos ejecutar en diferentes plataformas (PC, Tablet, Móvil, Xbox, etc) y es el mismo código el que se ejecuta en todas ellas. Pero esta potencia tiene un coste y este coste es el hecho de que cada plataforma tiene características diferentes y la aplicación se debe adaptar a ellas. Algunas de estas características son las siguientes: las dimensiones de la pantalla, el modo de interacción del usuario (táctil, ratón, lápiz, etc), las orientaciones de pantalla soportadas, etc.

 

Es habitual que estemos desarrollando una aplicación que necesite comportase de una manera u otra, en función del modo de interacción que en un momento determinado esté utilizando el usuario. Por ejemplo, imaginemos una aplicación que está compuesta de una lista vertical donde cada elemento a su vez es una lista horizontal y queremos que si el usuario está trabajando con un ratón las lista horizontales tengan el scroll deshabilitado para que el usuario, con la ruleta del ratón, no pueda hacer scroll horizontal y vertical a la vez en la lista principal y en las segundarias. Sin embargo, sí queremos que al utilizar el modo táctil pueda realizar el scroll en ambos sentidos.

 

Para ello necesitamos un mecanismo que informe a la aplicación de cuál es el modo de interacción que está utilizando el usuario en cada momento, y además, que sea capaz de detectar cuando se cambia entre un modo de interacción y otro, ya que por ejemplo, en una Tablet el usuario puede cambiar en cualquier momento entre ratón, táctil y lápiz.

 

En este artículo se presenta una posible solución a este problema para que la aplicación pueda adaptarse dinámicamente en función del modo de interacción del usuario.

 

Antes de comenzar:

El Visual State Manager es una de las piezas importantes en las aplicaciones UWP. El Visual State Manager junto al Adaptative Trigger permiten cambiar los estados visuales de la aplicación en función de las dimensiones de la misma, y en cada estado visual definir las propiedades de cualquier elemento de la interfaz.

 

Además, se pueden crear state triggers personalizados basados en determinadas características para cambiar entre diferentes estados visuales, para que la aplicación se adapte en función de esas características. Por ejemplo, se puede crear un state trigger personalizado para cambiar entre dos estados visuales en función de si la aplicación tiene conectividad a Internet o no. De este modo, la aplicación podría mostrar una configuración de interfaz u otra en función de la conectividad.

 

La solución:

Para solucionar el problema de cómo detectar el modo de interacción del usuario (ratón, táctil o lápiz) se hará uso de los state triggers personalizados. Crear un state trigger pesonalizado es sencillo, solamente se debe crear una clase que derive de StateTriggerBase y hacer uso del método SetActive de la clase base para disparar el estado visual.

 

A continuación se muestra el código de la clase InteractionModeTrigger que deriva de StateTriggerBase y que será la encargada de detectar el modo de interacción del usuario y activar el estado visual al que está sociado si procede.

 

Esta clase tiene una propiedad de dependencia llamada InputMode de tipo PointerDeviceType cuyo valor será establecido desde xaml y que indica el modo de interacción que disparará el estado visual. El tipo PointerDeviceType es un enumerado que indica el tipo de dispositivo de puntero (Touch, Pen, Mouse).

 

Por otro lado,  desde el constructor de la clase se subscribe a los eventos que van a detectar cuando el usuario está interactuando con la aplicación para poder detectar el modo de interacción. En este caso se han utilizado los eventos PointerMoved y PointerEntered del frame principal de la aplicación. Estos métodos se lanzarán, como su nombre indica, cuando el usuario mueva o comience a interactuar con la aplicación mediante un puntero.

 

En el manejador de eventos asociado a estos dos eventos (Page_Pointer) se hace uso del parámetro e que es de tipo PointerRoutedEventArgs que dispone de una propiedad llamada Pointer que recoge información del puntero con el que se ha interactuado. Dicha propiedad Pointer, a su vez dispone de otra propiedad llamada PointerDeviceType que es de tipo PointerDeviceType que indica el tipo de dispositivo de puntero.

 

Una vez que se ha obtenido el tipo de dispositivo con el que el usuario está interactuando, simplemente se debe comprobar si coincide con el valor de la propiedad InputMode y activar el estado visual con el método SetActive de la clase base.

 

Ejemplo de uso:

En el siguiente ejemplo se muestra una aplicación que contiene únicamente un TextBlock con un testo que cambia en función del modo de interacción del usuario. Para implementar este ejemplo se ha añadido la clase InteractionModeTrigger al proyecto y en el MainPage.xaml se ha añadido el siguiente código:

Analizando el código XAML, en el primer elemento hijo de la página se ha añadido un Visual State Manager que tiene tres estados visuales (TouchState, PenState y MouseState). Cada estado visual contiene un state trigger que disparará el estado, y estos triggers serán del tipo InteractionModeTrigger. Es necesario destacar que para poder utilizar el tipo InteractionModeTrigger se debe añadir el espacio de nombre en el elemento Page, en este caso:

 

Finalmente, en la propiedad Setter de cada VisualState se establecen las propiedades de los elementos de la UI que queremos que cambien al dispararse ese estado visual. En este ejemplo se cambia el valor de la propiedad Text del elemento «InteractionModeText», para que cada estado muestre el modo de interacción que está utilizando el usuario.

 

Si ejecutamos la aplicación veremos en el texto central el modo de interacción que se esté utilizado en cada momento. La primera imagen muestra el estado visual TouchState, la segunda imagen el estado PenState, y finalmente la tercera el estado MouseState.

 

Capture2
Capture3
Capture1