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