miércoles, 30 de noviembre de 2016

Tutorial Xamarin con Data Binding

Cuando uno mira ejemplos de uso de ciertas tecnologías, normalmente suelen mostrar la forma más sencilla de lograr el objetivo, pero sin reparar en la creación de una arquitectura base que después se pueda considerar válida para una aplicación "productiva". 

En este tutorial voy a mostrar cómo crear una simple aplicación (un conversor de medidas), pero utilizando el patrón Model-View-ViewModel (MVVM). 

Comencemos con filosofía. ¿Por qué quiero hacer algo así? La respuesta es porque si uso un patrón que define cómo se intercambian los datos entre la pantalla y el modelo podemos, entre otras cosas: generar pruebas, intercambiar modelos sin tener que reemplazar las vistas, utilizar métodos que pueden ser comunes a todas las pantallas, simplificar la creación de nuevas pantallas y, si otra persona conoce el patrón, le resultará más fácil respetarlo.

Entonces, si quisiera crear una aplicación de Android con Xamarin y Visual Studio que convierta un valor de kilómetros dado a millas, el procedimiento sería:

  • Crear una aplicación usando el template Android à Blank App (Android)
  • Modificar el layout para que contenga un textBox para ingresar los kilómetros
  • Un botón para hacer la conversión
  • Y un textView para mostrar la cantidad de millas resultantes
  • Y dentro del código del click del botón:

           o Buscamos el textbox de kilómetros y obtenemos el valor
           o Hacemos la conversión
           o Buscamos el textview de las millas y seteamos el dato


Bien, esto es sencillo y, ¡tiene que serlo! Pero veamos otra forma que me permita generarle pruebas, para hacer que funcione en distintos dispositivos (para eso usamos Xamarin) o, simplemente que permita extender las posibilidades de la aplicación.

Como dijo Jack el destripador, vamos por partes. El patrón MVVM plantea la separación de la lógica en un modelo, una vista y un viewmodel que interactúe entre los dos. Por otro lado, este patrón suele implementarse en conjunto con la técnica de two-way binding que le permite a la vista refrescarse cuando cambia el modelo y al modelo cuando cambia la vista. Existen muchos frameworks que utilizan estas técnicas, pero creo que el más nombrado últimamente es Angular (tanto JS como Angular2).

¡Pero construir eso va a ser muy complejo! No creo que sea para tanto, veamos los pasos:
  • Crear un proyecto usando el template Cross-Platform à Blank App (Xamarin.Forms Shared)
  • Crear un modelo que tenga los kilómetros, las millas y el método de conversión
  • Crear una vista de XAML que tenga un textbox (entry) para ingresar los kilómetros
  • Y un label para mostrar la cantidad de millas resultantes
  • Crear un ViewModel que pase el dato de los kilómetros al modelo (conversor), que     ejecute la conversión y avise, en este caso a la vista, que cambió la propiedad millas
  • Por último, vinculamos la vista con el ViewModel


Como dice Zamba: ¡Me aburro! Entonces, pasemos a la construcción del ejemplo:

Pueden encontrar el código completo en:

Creamos el proyecto:



Luego va a ofrecer la conexión con un equipo Mac para poder compilar para iPhone y, como en mi caso no tengo, voy a presionar el botón close. 





En esta pc, tampoco tengo el SDK del Universal Windows Plataform (que permite compilar para Xbox entre otros)





Vamos a probar que todo funcione como corresponde, seleccionado el dispositivo para la prueba y ejecutando el proyecto. En este caso, en el emulador con 4.5'' de pantalla y Android  versión 4.4:


Y luego debería mostrar la siguiente pantalla:



OK, comenzamos el desarrollo. Primero, dentro del proyecto Shared crearemos la carpeta Shared y dentro, las carpetas Models, Views y ViewModels. Este es solo un ejemplo, hay gente que prefiere tener la vista y el ViewModel en la misma carpeta, pero yo lo encuentro más claro de esta manera. 
La estructura debería quedar así:




Creamos la clase del modelo:



Creamos la vista. En este caso crearemos un Forms Xaml Page. Recordemos que la idea es tener separada la lógica de la presentación (la vista en Xaml) de la lógica que habilita o deshabilita controles, cambia colores, muestra u oculta secciones de la pantalla (el ViewModel):



Agregamos los controles:



Creamos la clase ConversorViewModel.cs, en la cual agregaremos las referencias a System.ComponentModel que nos permitirán usar la Interfaz INotifyPropertyChanged que brinda la posibilidad de que la vista se suscriba a los cambios en el ViewModel. Además, agregamos una referencia a nuestro modelo:



Y luego incorporamos las propiedades que serán utilizadas en la vista:



Buscamos el ConversorPage.xaml.cs y seteamos el BindingContext con el ViewModel:





Por último, le diremos a la aplicación que use la nueva pantalla que hemos creado, seteando el MainPage de la clase App del proyecto shared con una nueva instancia del ConversorPage:



Finalmente, lo probamos:





Esta solución tiene varios puntos a favor como, por ejemplo:
el ViewModel es el encargado de la trasformación del string proveniente de la pantalla al double que necesita el modelo.
Además, si quiero que cuando me ingresen un número negativo se ponga en rojo el valor de las millas, se puede resolver por medio de un método en el ViewModel, de esta manera logramos que se pueda testear.
Obviamente, cambiar colores se podría hacer directamente en la pantalla, pero hacerlo en el ViewModel lo hace explícito y no hay que recorrer el Xaml de la vista para encontrarlo.
Por otro lado, aunque se genera un acoplamiento entre la vista con el ViewModel y entre el ViewModel con el modelo, no hay acoplamiento entre la vista y el modelo. 


Algunos links para continuar investigando el tema:

Autor:
Marcelo Mosquera
.NET Architect