Hola MVVM(Model View ViewModel) PCL, Xamarin.Android, Xamarin.iOS, WP8.1 & W8.1
Working with MVVM Pattern on Xamarin and Windows Projects
El modelo de desarrollo MVVM fui introducido hace algunos años por microsoft inicialmente para el desarrollo en tecnologias WFP, Silverlight y Windows Phone, en que consiste este modelo mas que nada en el desarrollo de interfaces graficas responsivas a variables y acciones creadas en codigos sin la necesidad de instancear o crear un modelo que se comunique con la clase si no desde un archivo AXML o de interfaz grafica comunicarse directamente con nuestro codigo sin la necesidad de crear un puente entre ellos.
Si eres nuevo con el MVVM puedes dar una revision a este enlace con algo de teoria acerca del modelo http://www.codeproject.com/Articles/100175/Model-View-ViewModel-MVVM-Explained
Con esta apliacion ejemplo se agrega la posibilidad de crear interfaces unificadas aprovechando el uso de librerias portables y el modelo MVVM para la realizacion de interfaces responsibas a acciones y actualizacion de valores de nuestro modelos.
PCL
Primero agregaremos una libreria tipo PCL en la cual tendremos nuestros modelos y acciones para comunicarse con la interfaz grafica la configuracion de la PCL sera la siguiente:
Primero agregaremos el siguiente code snippet que nos dara la funcion de una clase de ayuda para instanciar acciones con propiedas como acciones y estado de las acciones la clase se llamara "DelegateCommand.cs" y el codigo es el siguiente:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace MvvmXamarin
{
public class DelegateCommand : ICommand
{
private readonly Action _handler;
private bool _isEnabled = true;
public DelegateCommand(Action handler)
{
_handler = handler;
}
public bool IsEnabled
{
get { return _isEnabled; }
set {
_isEnabled = value;
if (CanExecuteChanged != null)
{
CanExecuteChanged(this,EventArgs.Empty);
}
}
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_handler();
}
}
}
Seguido de esto crearemos un carpeta con el nombre "ViewModels" dentro de ella agregaremos nuestra clase tipo INotifyPropertyChanged en la cual estaremos realizando nuestro Code Behind el nombre de la clase sera el siguiente "Model.cs" y contendra el siguiente codigo:
using System;
using System.Windows.Input;
using System.ComponentModel;
using System.Threading;
namespace MvvmXamarin
{
public class Model: INotifyPropertyChanged
{
//Contexto
public readonly SynchronizationContext context;
//Constructor
public Model()
{
//Se inicializa el contexto
context = SynchronizationContext.Current;
}
//Nuestra propiedad text esta propiedad sera tomada graficamente como una Label, Etiqueta
private string text="Write Here";
//accesor get,set de la propiedad text
public string Text {
get
{
return text;
}
set
{
text = value;
//Despues de asignado el valor disparamos el evento de cambio de pripiedad
OnPropertyChanged("Text");
}
}
//Variable de numero de veces
private int Times = 0;
//variable de texto de boton
private string timesstring="Click";
//Accesor get,set de nuestro texto de boton
public string TimesString
{
get {
return timesstring;
}
set {
timesstring = value;
//Despues de asignado el valor disparamos el evento de cambio de pripiedad
OnPropertyChanged("TimesString");
}
}
//Accion(Comando) del boton
private ICommand clickEvent;
//Accesor get, set de la accion del boton
public ICommand ClickEvent
{
get {
//retornamos nuestro evento en caso de ser nulo generamos una instacia de nuestra clase DelegateCommand
//en la cual pasamos de parametro nuestro evento de click en este caso ExecuteClickCommand()
return clickEvent ?? new DelegateCommand(ExecuteClickCommand);
}
}
//Evento de click
private void ExecuteClickCommand()
{
//Aumentamos +1 el valor de nuestra variable Times
Times++;
//Asignamos un nuevo valor a nuestra variable TimesString para disparar el evento de cambio de propiedad
TimesString = string.Format("Clicked {0}",Times);
}
//evento PropertyChanged heredado de la clase INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
//Metodo OnPropertyChanged(string Name) heredado de la clase INotifyPropertyChanged
public void OnPropertyChanged(string Name)
{
//revisamos que nuestra accion no sea nula.
if (PropertyChanged == null)
return;
//Hacemos un envio al contexto indicando que se hizo un cambio de propiedad
context.Post((s)=>{
PropertyChanged(this, new PropertyChangedEventArgs((string)s));
},Name);
}
}
}
Una vez agregada estas dos clases tendremos realizada nuestra libreria la cual quedara con una estructura como esta.
WINDOWS PHONE 8.1
Acontinuacion procederemos a agregar una aplicacion tipo Windows Phone 8.1 y a este proyecto referenciaremos nuestra libreria PCL
En nuestra interfaz grafica agregaremos los siguientes componenetes
- 1 TextBlock
- 1 TextBox
- 1 Button
<Grid>
<!--
El valor de la propiedad Text de la label tendra un binding hacia nuestra variable Text dentro de nuestra PCL
-->
<TextBlock Text="{Binding Text}" HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="56" Width="380" FontSize="36"/>
<!--
El valor de la priedad Text del textbox tendra un binding a nuestra Varible Text con asignando dos propiedades mas
1 Mode=TwoWay indica que tendra las dos funciones asignacion y lectura
2 UpdateSourceTrigger=PropertyChanged indica que lanzara un evento de actualizacion de propiedad cada que se modifique su valor
-->
<TextBox Text="{Binding Text, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="10,90,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="380" Height="53"/>
<!--
El valor de la propiedad Content de nuestro boton tendra un binding hacia la varable TimesString
asi como la propÌedad Command a nuestro Comando ClickEvent ambos dentro de nuestra PCL
-->
<Button Content="{Binding TimesString}" Command="{Binding ClickEvent}" HorizontalAlignment="Left" Margin="10,159,0,0" VerticalAlignment="Top" Width="380"/>
</Grid>
Listo ahora como paso final dentro de nuestro constructor de nuestra clase MainPage indicaremos cual sera el contexto de la clase el cual sera una nueva instacia de nuestra clase Model quedando de la siguiente forma
public MainPage()
{
this.InitializeComponent();
//Asignamos una nueva instancia de nuestra clase Model al contexto de la vida
DataContext = new Model();
this.NavigationCacheMode = NavigationCacheMode.Required;
}
y listo ahora podemos probarla ya tenemos nuestra aplicacion lista y funcionando si cambiamos el valor de la caja de texto nuestra label actualizara su valor automaticamente asi como nuestro boton por cada click que demos ira actualizando su valor.
WINDOWS 8.1 STORE APP
Al igual que nuestra aplicacion de WP8.1 nuestra interfaz estara realizada de la misma manera debido que las intefaces axml nos hace un enlace directo con nuestra clase.
Añadimos la referencia de nuestra PCL a nuestra app
En nuestra interfaz grafica agregaremos los siguientes componenetes
- 1 TextBlock
- 1 TextBox
- 1 Button
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock HorizontalAlignment="Left" Margin="33,34,0,0" TextWrapping="Wrap" Text="{Binding Text}" VerticalAlignment="Top" Height="85" Width="367" FontSize="24"/>
<TextBox HorizontalAlignment="Left" Margin="33,152,0,0" TextWrapping="Wrap" Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="367" Height="114" FontSize="24"/>
<Button Command="{Binding ClickEvent}" HorizontalAlignment="Left" Content="{Binding TimesString}" Margin="30,284,0,0" VerticalAlignment="Top" Width="373" />
</Grid>
Al igual que en Windows Phone hay que indicar en nuestra clase MainPage el contexto que se usara quedando nuestro constructor de clase de la siguiente manera:
public MainPage()
{
this.InitializeComponent();
//Asignamos una nueva instancia de nuestra clase Model al contexto de la vida
DataContext = new Model();
}
Listo nuestra aplicacion de W8.1 ya deberia de funcionar a la perfeccion:
Debido a que las aplicaciones de microsoft tiene soporte completo para el modelo MVVM se puede aprevechar de manera mas comoda este modelo a continuacion seguiremos con las aplicaciones de Xamarin.Android y Xamarin.Ios para aprovechar de mejor manera este modelo de desarrollo.
XAMARIN.ANDROID
Agregamos la referencia a nuestra libreria PCL:Al igual que en los anteriores proyectos crearemos una interfaz grafica sencilla con
- 1 TextView
- 1 EditText
- 1 Button
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/Text" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/Field" />
<Button
android:text="Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/Button" />
</LinearLayout>
Debido a que Xamarin no contiene soporte directo para hacer bindings desde la interfaz axml a menos de que se use algun tipo de framework como mvvmcross o mvvmlight debemos de hacer algunos fragmento de codigo dentro de nuestra activity principal con el fin de poder aprovechar el modelo MVVM el codigo de la actividad principal quedaria de la siguiente manera:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace MvvmXamarin.Android
{
[Activity (Label = "MvvmXamarin.Android", MainLauncher = true)]
public class MainActivity : Activity
{
//Contexto
Model viewmodel;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
//Se inicializa el contexto
viewmodel = new Model ();
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
//Creamos nuestros objetos graficos
var et = FindViewById<EditText> (Resource.Id.Field);
var lbl = FindViewById<TextView> (Resource.Id.Text);
var btn = FindViewById<Button>(Resource.Id.Button);
//en nuestro boton hacemos directamente la llama a nuestro metodo
btn.Click += (sender, e) => viewmodel.ClickEvent.Execute(null);
//en nuestro evento textchanged de nuestro campo de texto actualizamos el valor de la variable Text de nuestro contexto
et.TextChanged += (sender, e) => {
viewmodel.Text = e.Text.ToString();
};
//Asignamos el evento PropertyChanged de nuestra variable contexto el cual nos retornara la accion realiza para asi hacer responsiva nuestra UI
viewmodel.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) =>
{
//Verificamos cual de las propiedades fue actualizada
if (e.PropertyName == "Text")
lbl.Text = viewmodel.Text;
else if (e.PropertyName == "TimesString")
btn.Text = viewmodel.TimesString;
};
}
}
}
y asi de facil ya tendremos nuestra aplicacion Xamarin.Android funcionando correctamente:
XAMARIN.IOS
Por ultimo y no menos importante crearemos nuestra aplicacion de Xamarin.iOS
Antes que nada añadiremos la referencia de nuestra PCL:
Nuestra interfaz contara con:
- 1 UILabel
- 1 UITextView
- 1 UIButton
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace MvvmXamarin.iOS
{
public partial class MainViewController : UIViewController
{
public MainViewController () : base ()
{
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
//Contexto
Model viewModel=null;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
//Agregamos color a nuestro fondo
View.BackgroundColor = UIColor.Gray;
// Perform any additional setup after loading the view, typically from a nib.
//Se inicializa el contexto
viewModel = new Model ();
//Creamos nuestra Label
UILabel lbl = new UILabel (new RectangleF(0,0,320, 50));
//Asignamos el texto de la label
lbl.Text = viewModel.Text;
//Asignamos la propiedad de autoajust de la label
lbl.AdjustsFontSizeToFitWidth = true;
//Creamos nuestra caja de texto
UITextView et = new UITextView (new RectangleF (0, 60, 320, 50));
//Asignamos el texto de nuestra caja
et.Text = viewModel.Text;
//Asiganamos el metodo de cambio de valor de nuestra caja
et.Changed += (object sender, EventArgs e) => {
//el valor de la variable Text de nuestro contexto es asiganado con el nuevo valor de la caja de texto
viewModel.Text = et.Text;
};
//Creamos nuestro boton
UIButton btn = new UIButton(new RectangleF(0, 120, 320, 50));
//Asignamos el texto del boton
btn.SetTitle(viewModel.TimesString, UIControlState.Normal);
//asignamos el evento de click en el boton
btn.TouchUpInside += (s,e) => viewModel.ClickEvent.Execute(null);
//Agregamos efecto de toque al boton
btn.ShowsTouchWhenHighlighted = true;
//Al igual que en la aplicacion de android
//Asignamos el evento PropertyChanged de nuestra variable contexto el cual nos retornara la accion realiza para asi hacer responsiva nuestra UI
viewModel.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) =>
{
//Verificamos cual de las propiedades fue actualizada
if (e.PropertyName == "Text")
lbl.Text = viewModel.Text;
else if (e.PropertyName == "TimesString")
btn.SetTitle(viewModel.TimesString, UIControlState.Normal);
};
//Añadimos nuestra label a la vista principal
View.Add (lbl);
//Añadimos nuestro campo de texto a la vista principal
View.Add (et);
//Añadimos nuestro boton a la vista principal
View.Add (btn);
}
}
}
A continuacion ya podremos probar nuestra aplicacion responsiva Xamarin.iOS utilizando el modelo MVVM
Codigo fuente en GitHub: https://github.com/AlejandroRuiz/Mono/tree/master/MvvmCrossXamarin
Desarrollando aplicaciones multiplataforma en 60 min con Xamarin aprovechando el modelo MVVM: http://channel9.msdn.com/Blogs/DevRadio/Microsoft-DevRadio-Developing-for-Windows-8-in-1-2-the-Time-60min-Challenge-Buidling-Cross-Platform-
Seria un post extremadamente largo el detallar el uso de cada una de las interfaces quize redondear todo y solo poner los puntos importantes de cada plataforma en caso de que tengan alguna duda en concreto con el post o alguna de las plataformas con gusto puedo resolverla mediante mi twitter @alejandroruizva o en mi correo elgoberlivel@gmail.com espero y esta informacion sea de su ayuda, hasta la proxima.












Hi Author just now i found your blog its really awesome. Keep this work. It will more helpful for xamarin app developers.
ResponderEliminarHire affordable Xamarin Developer