El patrón MVVM en Xamarin Forms

En el anterior artículo vimos una breve introducción al patrón de diseño MVVM. Tal como decía en ese post, está considerado una buena práctica el uso de dicho patrón a la hora de desarrollar un proyecto, tanto con Xamarin tradicional, como con Xamarin Forms. El objetivo de esta entrada es continuar profundizando en el desarrollo con Xamarin Forms aplicando MVVM.

Los orígenes de MVVM

En el año 2004, un grupo de desarrollo de Microsoft trabajaba en un proyecto denominado “Avalon”, más conocido por su nombre definitivo WPF (Windows Presentation Foundation). El propósito de dicho proyecto era permitir el desarrollo de aplicaciones de escritorio más completas y con un aspecto visual mucho más logrado y complejo de lo que era posible con Windows Forms.

Al año siguiente John Gossman (miembro del equipo de desarrollo de “Avalon”), en un artículo de la MSDN,  mostraba al público el patrón MVVM. En el artículo, MVVM se presenta como una variación del patrón MVC ajustado a “WPF” y a su sistema de enlace a datos, aunque realmente es una adaptación del patrón  “presentation model” creado por el mítico Martin Fowler.

Elementos del patrón MVVM

La finalidad principal del patrón MVVM (Modelo Vista Vista-Modelo) es tratar de desacoplar lo máximo posible la interfaz de usuario de la lógica de la aplicación. Veamos a grandes rasgos sus partes principales:

El modelo

Representa la capa de datos y/o la lógica de negocio, también denominado como el objeto del dominio. El modelo contiene la información, pero nunca las acciones o servicios que la manipulan. En ningún caso tiene dependencia alguna con la vista.

La vista

La misión de la vista es representar la información a través de los elementos visuales que la componen. Las vistas en MVVM son activas, contienen comportamientos, eventos y enlaces a datos que, en cierta manera, necesitan tener conocimiento del modelo subyacente. En Xamarin Forms podemos crear nuestras interfaces a través de código C# o XAML.

Modelo de vista (ViewModel)

El ViewModel (modelo de vista) es un actor intermediario entre el modelo y la vista, contiene toda la lógica de presentación y se comporta como una abstracción de la interfaz. La comunicación entre la vista y el viewmodel se realiza por medio los enlaces de datos (binders).

mvvm-1

MVVM en Xamarin Forms, interacción con el usuario

Vamos a tomar como punto de partida el ejemplo visto en la entrada anterior, la idea es añadir a dicho ejemplo un elemento entry en el cual el usuario pueda introducir un texto y a su vez este se vaya reflejando en un elemento de tipo label.

Contábamos con una estructura MVVM lo más sencilla posible, teníamos un ViewModel  denominado MainViewModel con una propiedad llamada “MyMessage”:

public class MainViewModel
{
     private string _myMessage;
 
     public MainViewModel()
     {
          Message = "Hello MVVM!";
     }
 
 
     public string MyMessage
     {
          get { return _myMessage; }
          set { _myMessage = value; }
     }
}

Además, contabamos con una vista que utilizaba como contexto “MainViewModel” enlazando desde el atributo “text” de un label a la propiedad “MyMessage”:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="simpleMVVM.Views.MainView">
     <Label Text="{Binding MyMessage}" 
          VerticalOptions="Center" 
          HorizontalOptions="Center" />
</ContentPage>
namespace simpleMVVM.Views
{
    public partial class MainView : ContentPage
    {
        public MainView()
        {
            InitializeComponent();
            BindingContext = new MainViewModel();
        }
    }
}

Modos de enlace a datos

Antes de continuar con el ejemplo veamos como funcionan los modos de enlace a datos. En Xamarin Forms el modo de enlace a datos se define con la palabra reservada “mode”, la cual nos indica como se comporta el mismo. Contamos con los siguientes:

  • OneWay: es el valor por defecto, indica que el enlace se produce en un solo destino, el de lectura. Si el valor del elemento de la vista cambia, no enlazará con el ViewModel asociado.
  • OneWayToSource: este valor enlaza en un único sentido la View al ViewModel.
  • TwoWay: en este caso indica que el enlace es bidireccional. En un primer momento, la vista toma el valor de la propiedad del ViewModel y si este cambia en la vista es enviado de vuelta hacia el ViewModel.

Continuando con el ejemplo, vamos a añadir un elemento de tipo entry, que esté enlazado a la propiedad “myMessage” de forma bidireccional, un elemento label que está enlazado con el modo por defecto (oneWay) y un stacklayout que haces las veces de contenedor, debido a que las páginas no pueden contener más de un elemento.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage 
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="simpleMVVM.Views.MainView">
    <StackLayout>

        <Entry Text="{Binding MyMessage, Mode=TwoWay}" 
              VerticalOptions="Center" 
              HorizontalOptions="Center" />
        
        <Label Text="{Binding MyMessage}" 
              VerticalOptions="Center" 
              HorizontalOptions="Center" />
    
    </StackLayout>
</ContentPage>

Al hacer debug sobre el código anterior, observarás que aparentemente todo está funcionando correctamente. Si  examinas el contenido de la propiedad MyMessage verás que el valor se ha actualizado correctamente, pero el texto del elemento label no se actualiza, esto es debido a que no se ha notificado a la vista que el valor de la propiedad ha cambiado. Es aquí donde entra en juego la interfaz INotifyPropertyChanged.

Notificación de cambios (INotifyPropertyChanged)

La interfaz INotifyPropertyChanged define un método llamado RaisePropertyChanged y un evento llamado PropertyChanged, que debemos implementar. Dicho evento será lanzado cuando se actualice el valor de la propiedad deseada del ViewModel y notificará a la View que evaluará de nuevo el valor de dicha propiedad. Para que esto funcione correctamente es necesario ejecutar el método RaisePropertyChanged en el setter de la propiedad.

public class MainViewModel
{
     private string _myMessage;
 
     public MainViewModel()
     {
          Message = "Hello MVVM!";
     }
 
     public string MyMessage
     {
          get { return _myMessage; }
          set
          {
               _myMessage = value;
               RaisePropertyChanged("MyMessage");
          }
     }
     
     private void RaisePropertyChanged(string propertyName)
     {
          var handle = PropertyChanged;
          if (handle != null)
               handle(this, new PropertyChangedEventArgs(propertyName));
     }
 
     public event PropertyChangedEventHandler PropertyChanged;
}

Dado que todos los ViewModels o la mayoría, van a hacer uso de la interfaz INotifyPropertyChanged, sería interesante crear un ViewModel base, del cual hereden demás. Por otro lado, vamos a hacer uso del atributo CallerMemberName con el cual aseguras que el nombre de la propiedad que llama al método RaisePropertyChanged es el correcto sin tener que indicarlo explícitamente.

public class ViewModelBase
{
     private void RaisePropertyChanged([CallerMemberName] string propertyName = null)
     {
          var handle = PropertyChanged;
          if (handle != null)
               handle(this, new PropertyChangedEventArgs(propertyName));
     }
 
     public event PropertyChangedEventHandler PropertyChanged;
}

Tras refactorizar el MainViewModel quedaría tal que así:

public class MainViewModel : ViewModelBase
{
     private string _myMessage;
 
     public MainViewModel()
     {
     }
 
     public string MyMessage
     {
          get { return _myMessage; }
          set
          {
               _myMessage = value;
               RaisePropertyChanged();
          }
     }
}

Este sería el resultado, tras ejecutar el proyecto:

Comandos

Nos faltaría por ver la interacción a priori más básica que puede realizar un usuario sobre una app, pulsar un botón y que ocurra algo. Para llevar a cabo esta funcionalidad se aplica el patrón Command (comando) cuyo objetivo no es otro que encapsular la invocación de un método de otro objeto.

Debes depender de abstracciones, no de concreciones Click Para Twittear

Para aplicar este mecanismo en Xamarin.Forms junto con MVVM el ViewModel asociado a la vista debe exponer una propiedad que implemente la interfaz ICommand. El valor de dicha propiedad puede ser asignado a elementos visuales como botones, a través de la propiedad comando vía enlace a datos. Esto a su vez ejecutará el método Execute de dicha interfaz, la cual además define un método CanExecute que permite verificar si el comando puede ser ejecutado o no.

Al igual que ocurría con la implementación de la interfaz INotifyPropertyChanged, cuando utilizamos comandos se tiende a repetir más código del necesario, por esta razón se utilizan implementaciones reutilizables como DelegateCommand.  Esta implementación es una clase que implementa la intefaz ICommnad que recibe dos parámetros en su constructor del tipo Action y Func, el método a ejecutar (Execute) y el método que indica si se puede ejecutar o no(CanExecute), respectivamente.

public class DelegateCommand : ICommand
{
     private Action _execute;
     private Func<bool> _canExecute;
 
     public DelegateCommand(Action execute, Func<bool> canExecute = null)
     {
          _execute = execute;
          _canExecute = canExecute;
     }
 
     public bool CanExecute(object parameter)
     {
          if (_canExecute == null)
               return true;
 
          return _canExecute();
     }
 
     public event EventHandler CanExecuteChanged;
 
     public void Execute(object parameter)
     {
          if (_execute != null)
               _execute();
     } 
     
     public void RaiseCanExecuteChanged()
     {
          var handle = CanExecuteChanged;
          if (handle != null)
               handle(this, new EventArgs());
     }
}

Si no estás muy familiarizado con C#, los tipos Action y Func<bool>, son delegados genéricos. Action simplemente es un delegado que no devuelve nada y en este caso tampoco recibe ningún parametro; y Func<bool>, tampoco tiene parámetros y en este caso devuelve un booleano. Por sino lo sabes, un delegado no es más que un tipo de dato que representa un puntero a un método.

Continuando con el ejemplo, vamos a añadir a la view del ejemplo anterior un botón, el cual al ser pulsado incrementará un contador que se mostrará en el elemento label de la misma. Para ello se le asigna el commando MyCommand a la propiedad command del botón, el cual se implimentará en el correspondiente ViewModel.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage 
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="simpleMVVM.Views.MainView">
    <StackLayout>

        <Button Text="Sent" 
              Command="{Binding MyCommand}"
              VerticalOptions="Center" 
              HorizontalOptions="Center" />

        <Label Text="{Binding MyMessage}" 
              VerticalOptions="Center" 
              HorizontalOptions="Center" />
    
    </StackLayout>
</ContentPage>

En el MainViewModel se crea una propiedad del tipo ICommand denominada MyCommand, cuya variable privada será del tipo DelegateCommand que hemos implementado con anterioridad. En el getter de esta propiedad, se instanciará DelegateCommand recibiendo como parámetro el método que contiene la lógica para incrementar el contador, quedando el MainViewModel tal que así:

public class MainViewModel : ViewModelBase
{
 	 private int _counter;
     private DelegateCommand _myCommand;
     
     void counterCommandExecute()
     {
     	  _counter++;
          RaisePropertyChanged("MyMessage");
     }
     
     public MainViewModel()
     {
     	_counter = 0;
     }
 
     public string MyMessage
     {
          get { return string.Format("{0} times", _counter); }
     }
     
     public ICommand MyCommand
     {
          get { return _myCommand = _myCommand ?? new DelegateCommand(counterCommandExecute); }
     }
}

Tras ejecutar la app se puede observar que al pulsar el botón el contador se va incrementando correctamente:
commands

Resumen

En este artículo se han expuesto los conceptos básicos para aplicar el patrón MVVM a la hora de realizar las interacciones básicas de los usuarios con Xamarin Forms, donde destacan las notificaciones y los comandos.

Continuaré profundizando en próximas entradas en el desarrollo con Xamarin, seguiré exponiendo conceptos fundamentales como la navegación entre páginas, contenedores de dependencias, persistencia de datos en el dispositivo, consumo de APIS, etc.

Si te ha gustado la entrada valora y comparte en tus redes sociales. No dudes en comentar dudas, aportes o sugerencias, estaré encantado de responder.

Este artículo se distribuye bajo una Licencia Creative Commons Reconocimiento-CompartirIgual 4.0 Internacional (CC BY-SA 4.0)

licencia-cc

Xamarin Forms, apps nativas multiplataforma. Introducción

Hoy en día, crear aplicaciones móviles para múltiples plataformas supone todo un reto para los desarrolladores. Tratar de abordar un desarrollo usando los toolkits nativos de cada sistema requiere de una cantidad enorme de conocimientos específicos para cada uno de ellos. Nos encontraremos con un panorama enormemente complejo, con múltiples lenguajesvarios entornos de desarrolloAPIs de todos los colores. Xamarin trata de poner solución a esta problemática ofreciéndonos un conjunto de herramientas que nos permitirá desarrollar aplicaciones nativas, compartiendo la mayor cantidad de código, entre las plataformas más importantes: AndroidiOS y Windows Phone.

Este artículo va dirigido a desarrolladores que estén interesados en comenzar a crear aplicaciones cross-platform nativas con Xamarin, sería recomendable que estuviesen familiarizados con el lenguaje C# y/o con el SDK de iOS o Android, aunque no es imprescindible. En la primera parte de la entrada trataré algunas generalidades como la problemática del desarrollo multiplataforma, las características claves de Xamarin, la instalación y puesta en marcha y la cuando elegir entre Xamarin Tradicional o Xamarin Forms. En la segunda parteme centraré en Xamarin.Forms y en sus elementos clave;  por último, veremos una pequeña introducción a la implementación del patrón MVVM en Xamarin Forms.

La problemática del desarrollo multiplataforma

Como podemos observar en la siguiente tabla, cada plataforma cuenta con su propio entorno de desarrollo integrado (IDE), con uno o varios lenguajes de programación, con un lenguaje especifico para las vistas, y por si fuera poco los patrones de diseño a aplicar difieren entre las diferentes plataformas.

iOSAndroidWindows
IDEXCodeAndroid StudioVisual Studio
LenguajeObjectiveC o SwiftJavaC#
VistasStoryboard o XIBSAXMLXAML
Patrón de diseñoMVCMVCMVVM

Abordar todos estos aspectos requiere de una cantidad de enorme de conocimientos por parte del desarrollador y, por otro lado, no parece ser eficiente tener que reescribir la lógica de negocio para cada uno de los sistemas.

¿Que opciones tenemos? Apps híbridas o nativas

Tradicionalmente, cuando hablamos de tecnologías multiplataforma, pensamos en un enfoque minimalista: reducir nuestra implementación/desarrollo a un mínimo denominador en todas las plataformas. Esto es lo que se propone en las aplicaciones híbridas desarrolladas con tecnologías del tipo PhoneGap/Cordova, en las cuales escribimos códigohtml y javascript  que tiene que ser interpretado por un navegador web. Este tipo de soluciones no consigue igualar la respuesta y la experiencia de usuario de una app nativa. Por poner un ejemplo, Mark Zuckerberg (CEO de Facebook), reconoció que el mayor error que habían cometido en la trayectoria de Facebook fue crear  en un primer momento una app híbrida en lugar de una nativa.

Mark Zuckerberg: nuestro mayor error ha sido crear en un principio una app híbrida en lugar de nativa Click Para Twittear

Xamarin nos ofrece un enfoque multiplataforma diferente, ya que nos facilita la tarea de desarrollar cualquier tipo de aplicación/juego de forma nativa para las plataformas más usadas: iOS, Android y Windows. Para ello nos brinda acceso al 100% de las APIS nativas + las APIs comunes de .NET, con un mismo lenguaje de programación C#.

Existen alternativas interesantes a Xamarin que también proponen un enfoque nativo, como puede ser React Native de Facebook (aún en beta) , que permite escribir apps para android e iOS Nativas en Javascript con el estilo de React. O, Ruby Motion, una tecnología que nos permite realizar apps para Android e iOS con Ruby, si RoR forma parte de tu stack esta plataforma es más que interesante. Aunque sin duda, por aceptacióncuota, comunidad y evolución brilla con luz propia Xamarin.

react-native-rubymotion

Características

 

  • Compartir código:Además de compartir un mismo lenguaje y entorno de desarrollo, podemos utilizar un mismo patrón de desarrollo.
  • Completa cobertura de las APIs de iOS y Android: Tenemos todas las APIs disponibles con C#, cualquier cosa que se pueda hacer con Objective-C/Swift o Java, se puede hacer con C# y Xamarin.

api-xamarin

  • Aplicaciones nativas:Las aplicaciones desarrolladas con Xamarin son 100% nativas.
  • Siempre actualizado: Xamarin suele añadir soporte el mismo día del lanzamiento oficial de una actualización.
  • Open source y gratis: Tras la compra de Xamarin por parte de Microsoft, pasó a ser Open Source y gratuito.

Instalación de Xamarin

En Mac OS
Para instalar Xamarin en Mac OS, tan solo tenemos que descargar el instalador y a continuación un asistente nos guiará en la instalación de Xamarin Studio y los SDKs  de las diferentes plataformas.

En Windows:
Para comenzar a trabajar con Xamarin en Windows se debe realizar la descarga de Visual Studio Community. Tras ejecutar el instalador tenemos la posibilidad de elegir entre una instalación típica o personalizada. Escogemos personalizada y seleccionamos el checkbox de Xamarin dentro del apartado de desarrollo móvil multiplataforma.

Para compilar y acceder a opciones como el editor visual de iOS necesitamos de forma inevitable tener conexión con un Mac. Todo el proceso de conexión se realiza de forma prácticamente transparente desde Visual Studio a través de la herramienta Xamarin Mac Agent por medio de una conexión ssh.

Xamarin Tradicional vs Xamarin Forms

Antes de empezar a desarrollar con  Xamarin debemos elegir si utilizar Xamarin Tradicional(Xamarin.iOS y Xamarin.Android) o Xamarin Forms para crear nuestro proyecto, aunque algunos expertos de la comunidad como @_jmgomez_ ya plantean algunas soluciones “fuera de la caja” (artículo).

En Xamarin tradicional, se puede compartir toda la lógica de la aplicación entre las diferentes plataformas, a excepción de la interfaz de usuario, la cual será independiente para cada una de las mismas. En cambio, Xamarin Forms añade una capa de abstracción sobre la UI que permite compartir, además de la lógica de negocio, la interfaz de usuario, aumentando consigo la reutilización de código.

¿Cuando escoger uno u otro?
Xamarin tradicional es idóneo cuando se requiere un nivel muy elevado de personalización de la interfaz de usuario para cada una de las plataformas, siendo más importante el nivel personalización de la UI que la cantidad de código compartido; mientras que Xamarin.Forms es la mejor opción cuando las aplicaciones requieren menos especificidad en la UI y hacen más énfasis en compartir la mayor cantidad posible de código.

xamarin-1

Xamarin Forms

La capa de abstracción que añade Xamarin Forms a la UI nos facilita la tarea de crear interfaces de usuarios nativas compartidas, ya que cada uno de los elementos de dicha abstracción son mapeados a elementos propios de cada una de las plataformas.

XAML

Las interfaces en Xamarin Forms se pueden definir tanto con código C# desde Code Behind, como con XAML, mi recomendación es utilizar este último para aprovechar su enfoque de separación de responsabilidades entre diseño y codificación.

XAML (eXtensible Application Markup Language) es un lenguaje declarativo basado en XML y pensado para escribir la interfaz gráfica de una aplicación de forma textual y ordenada, aparece por primera vez en la versión 3.0 del Framework de .NET.

Una de las características más importantes de XAML es que todos los elementos que definamos en este son instanciados por el CLR y quedan accesibles como objetos desde código, sin necesidad de realizar de nuevo la declaración de los mismos en Code Behind, gracias al mecanismo de las clases parciales.

XAML permite construir la jerarquía de objetos de componen la interfaz. Con el uso de etiquetaspodemos definir cada uno de los elementos visuales, y con el uso de atributos definimos la apariencia y el comportamiento de cada uno de los elementos.

Veamos un ejemplo de una misma interfaz definida en XAML y C#:

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyApp.MainPage">
    <TabbedPage.Children>
        <ContentPage Title="Profile" Icon="Profile.png">
            <StackLayout Spacing="20" Padding="20" VerticalOptions="Center">
                <Entry Placeholder="Username" Text="{Binding Username}"/>
                <Entry Placeholder="Password" Text="{Binding Password}" IsPassword="true"/>
                <Button Text="Login" TextColor="White" BackgroundColor="#77D065" Command="{Binding LoginCommand}"/>
            </StackLayout>
        </ContentPage>
        <ContentPage Title="Settings" Icon="Settings.png">
            <!-- Settings -->
        </ContentPage>
    </TabbedPage.Children>
</TabbedPage>
using Xamarin.Forms;

var profilePage = new ContentPage {
    Title = "Profile",
    Icon = "Profile.png",
    Content = new StackLayout {
        Spacing = 20, Padding = 50,
        VerticalOptions = LayoutOptions.Center,
        Children = {
            new Entry { Placeholder = "Username" },
            new Entry { Placeholder = "Password", IsPassword = true },
            new Button {
                Text = "Login",
                TextColor = Color.White,
                BackgroundColor = Color.FromHex("77D065") }}}
};

var settingsPage = new ContentPage {
    Title = "Settings",
    Icon = "Settings.png",
    (...)
};

var mainPage = new TabbedPage { Children = { profilePage, settingsPage } };

Pages

Las páginas son elementos contenedores que representan una pantalla de la aplicación. Xamarin.Forms.Page representa un ViewController en iOS, una Page en UWP, en Android cada página se comporta como un Activity, pero no lo son.
xamarin forms pages
ContentPage: es la página más simple, cuenta con una única vista donde añadir contenido.
MasterDetailPage: gestiona dos paneles de información.
NavigationPage: gestiona la navegación entre paginas.
TabbedPage: facilita el acceso a las subpáginas mediante tabs.
TemplatedPage: muestra el contenido a pantalla completa, permite utilizar plantillas para definir el contenido.
CarouselPage: permite el acceso a las subpáginas haciendo un gesto de scroll lateral.

Layouts

Los layouts son elementos contenedores de otros layouts o vistas, son especialmente necesarios ya que las páginas sólo contener un elemento hijo. Lo utilizaremos para establecer la posición y alineación de los elementos que contienen.
xamarin-forms-layoutsLos más destacados son:
ContentView: permitir crear elementos más complejos a partir del mismo.
ScrollView: si el contenido lo requiere permite hacer scroll.
StackLayout: organiza y posiciona otros controles, es uno de los layouts más utilizados, por defecto los apila verticalmente.
AbsoluteLayout: hace uso posiciones absolutas para posicionar los elementos.
GridLayout: Permite la organización de elementos por medio de filas y columnas.
RelativeLayout: facilita el posicionamiento de los elementos mediante constraints.

Views (controles)

Las Views, también denominados controles o widgets, hacen referencia a los elementos visuales como pueden ser botones, labels, o textboxs. Xamarin Forms nos provee de multiples views:

controls-xamarin
Puedes ver la descripción de cada uno de los controles y como se visualizan en las diferentes plataformas desde aquí.

Creando nuestra primera app Xamarin.Forms

Para crear nuestra app abrimos Visual Studio o Xamarin Studio, dependiendo si estáis en Windows o Mac, respectivamente, en mi caso voy a usar Xamarin Studio. A continuación, nos dirigimos a nueva solución para crear un nuevo proyecto partiendo de la plantilla de aplicación multiplataforma “Forms App”:

app-xamarin-forms-1

En la siguiente pantalla del asistente rellenamos los campos del nombre de la app y del identificador de la organización, seleccionamos las plataformas Android e iOS, en el caso de estar en Visual Studio también podriamos incluir en nuestro proyecto UWP.

Shared Project (SP) vs Portable Class Library (PCL)

Seguidamente nos encontramos con que debemos escoger entre un SP (Shared Project)  y una PCL (Portable Class Library). Aunque ambos persiguen el mismo objetivocompartir la mayor cantidad posible de código entre plataformas, difieren en varios aspectos.

Las PCL a diferencia de los SP, generan un asembly reutilizable (dll) que puede ser consumido fuera de la solución. Es importante tener en cuenta que en las PCL no se tiene acceso completo al framework de .NET.

Los SP no se compilan como un ensamblado a parte, sino como parte de cada proyecto al que están referenciado, como si fuese código del propio proyecto. Los SP permiten hacer uso de directivas que permiten generar código especifico para cada una de las plataformas.

En nuestro caso usaremos la PCL:

app-xamarin-forms-2

Estructura de una solución Xamarin.Forms

Una vez finalizado el asistente, se generará una solución estructurada en tres proyectos:

app-xamarin-forms-3

El primero de los proyectos corresponde a la PCL, el  cual contendrá el código compartido de la aplicación para todas las plataformas. A continuación tenemos los proyectos específicos de iOS y Android.

En el proyecto compartido, a modo de ejemplo se ha generado una página llamada helloFormsPage que cuenta con un elemento de tipo ContentPage que a su vez contiene un control Label en el que se muestra un texto de bienvenida.

HelloFormsPage está formado por dos ficheros por un lado tenemos el XAML y por otro el code behing en C# los cuales corresponden a una misma clase distribuida en dos ficheros, a este concepto se le denomina clases parciales. Por lo tanto el XAML no es más que una clase parcial de nuestro Code Behind, que se completa con el fichero que lleva el  mismo nombre que el XAML pero con la extensión .cs.

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
        xmlns:local="clr-namespace:helloForms" 
        x:Class="helloForms.helloFormsPage">
    <Label Text="Welcome to Xamarin Forms!" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

En el proyecto compartido, además de contar con la clase de ejemplo helloFormsPage, tenemos una clase llamada App, en la cual se indica cual será la primera página a mostrar en todas las plataformas, esto se realiza en el constructor de la misma. Además cuenta con otros métodos que nos permiten ejecutar acciones según el estado de la aplicación.

namespace helloForms
{
    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();
            MainPage = new helloFormsPage();
        }
        protected override void OnStart()
        {
            // Handle when your app starts
        }
        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }
        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}

 

En el proyecto de Android tenemos una clase denominada MainActivity que cuenta con un método OnCreate() en el cual inicializamos la app del proyecto compartido:

namespace helloForms.Droid
{
    [Activity(Label = "helloForms.Droid", Icon = "@drawable/icon", Theme = "@style/MyTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;
            base.OnCreate(bundle);
            global::Xamarin.Forms.Forms.Init(this, bundle);
            LoadApplication(new App());
        }
    }
}

 

Por último, en iOS, disponemos de la clase AppDelegate en la cual cargaremos la app del proyecto compartido:

namespace helloForms.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App());
            return base.FinishedLaunching(app, options);
        }
    }
}

 

Si, ejecutamos el proyecto en los emuladores de iOS y Android obtendríamos el siguiente resultado:

app-xamarin-forms-4

El patrón MVVM en Xamarin Forms

Aunque no es obligatorio utilizar el patrón MVVM para desarrollar una aplicación con Xamarin Forms, está considerado una buena práctica hacer uso del mismo. A continuación veremos algunos conceptos claves para entender el por qué.

MVVM (Modelo Vista Vista-Modelo) es un patrón de diseño derivado de MVC, cuyo objetivo es tratar de desacoplar al máximo la interfaz de usuario de la lógica de la aplicación,  para ello hace uso de un lenguaje de marcado en las vistas, XAML en el caso de Xamarin Forms. El modelo realiza la misma función que en MVC, representa la capa de datos y/o la lógica de negocio de nuestro proyecto, en ningún caso tiene dependencia alguna de la vista.

El ViewModel (modelo de vista) es un actor intermediario entre el modelo y la vista, contiene toda la lógica de presentación y se comporta como una abstracción de la interfaz. La comunicación entre la vista y el viewmodel se realiza por medio los enlaces de datos (binders).

mvvm-1

A continuación vamos a crear un ejemplo sencillo para mostrar como implementar en una solución Xamarin forms el patrón MVVM.

Vamos a partir de un nuevo proyecto Xamarin.Forms utilizando una librería portable. En la PCL creamos las carpetas Views, ViewModels, y dentro de ViewModels la carpeta Base. Quedando la estructura de la solución tal que así:

mvvm-2

Una vez creadas las carpetas, añadimos la página principal, para ello hacemos clic derecho sobre la carpeta Views, le damos a la opción agregar nuevo archivo, seleccionamos “Forms ContentPage”,  lo llamamos MainView y añadimos el siguiente código:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="simpleMVVM.Views.MainView">
     <Label Text="{Binding MyMessage}" 
          VerticalOptions="Center" 
          HorizontalOptions="Center" />
</ContentPage>

En el XAML anterior podemos observar que en el atributo text  del elemento Label hemos utilizado lo que se denomina una expresión de enlace a datos, en próximos posts veremos con más detalle su funcionamiento por ahora nos basta con saber que cuando el compilador se encuentra con una expresión entre llaves la interpreta,y, en este caso, al encontrarse con la palabra reservada Binding, lo que hace es enlazar el valor de la propiedad MyMessage la cual definiremos en el ViewModel.

Lo siguiente que vamos a hacer es crear nuestro primer ViewModel. Un ViewModel no es más que una clase en la que se expone la información con propiedades públicas. Por lo tanto, agregamos dentro de la carpeta ViewModels una clase a la que vamos a denominar MainViewModel con una propiedad llamada “MyMessage”:

public class MainViewModel
{
     private string _myMessage;
 
     public MainViewModel()
     {
          Message = "Hello MVVM!";
     }
 
 
     public string MyMessage
     {
          get { return _myMessage; }
          set { _myMessage = value; }
     }
}

A continuación, tenemos que enlazar nuestro ViewModel con el contexto de datos de la página. Para ello asignamos en la propiedad BindingContext de la nuestra vista una instancia de nuestro ViewModel. El Code Behind de la vista quedaría así:

namespace simpleMVVM.Views
{
    public partial class MainView : ContentPage
    {
        public MainView()
        {
            InitializeComponent();
            BindingContext = new MainViewModel();
        }
    }
}

Por último, tan solo nos queda indicar cual es la página principal en la propiedad MainPage de la clase App:

public App()
{
    InitializeComponent();
    MainPage = new MainView();
}

Esta sería la estructura MVVM más sencilla posible, en principio nos sirve para ilustrar los fundamentos básicos. No obstante, no hemos cubierto  conceptos como los modos de enlace a datoslas notificaciones y los comandos, imprescindibles para conseguir una de interacción completa del usuario, quedarán pendientes para próximas entradas.

Resumen

En este artículo he tratado de sentar las bases, en la medida de lo posible, de Xamarin y en particular de Xamarin Forms, me he dejado muchos temas en el tintero, y en otros he sido muy superficial, cómo por ejemplo en la introducción del patrón MVVM, pero el post estaba creciendo exponencialmente.

La idea es continuar profundizando en próximas entradas en el desarrollo con Xamarin, tanto tradicional como con forms. Espero haber facilitado tu transición a Xamarin, o por lo menos haber sabido trasladarte alguna de sus virtudes.

Si te ha gustado la entrada valora y comparte en tus redes sociales. No dudes en comentar dudas, aportes o sugerencias, estaré encantado de responder.

Este artículo se distribuye bajo una Licencia Creative Commons Reconocimiento-CompartirIgual 4.0 Internacional (CC BY-SA 4.0)

licencia-cc