Windows Phone 7 – Tutorial III–Modelo de Ejecución

Antes de la anterior entrada, debería haber ido esta y es como es el modelo de ejecución en Windows Phone, siempre debemos de entenderlo en cualquier tecnología a la que nos dediquemos para entender el comportamiento de la aplicación a la hora de ejecutarse.

Lo primero que debemos de entender es que en Windows Phone solo se ejecuta una aplicación en un determinado momento, con lo que si un usuario se sale de nuestra aplicación y se va a otra, nuestra aplicación se descargara de memoria. Lo que si nos proporciona Windows Phone es un mecanismo para que podamos salvar el estado de nuestra aplicación cuando el usuario se salga de ella y poder restaurarlo cuando vuelve a ejecutar nuestra aplicación.

 

Para entender el modelo de aplicación de Windows Phone debemos de conocer ciertos términos:

  • Tombstoning: Mecanismo que permite que nuestra aplicación este “siempre corriendo”, incluso cuando ha sido desactivado por el usuario, aquí tenéis un diagrama de como funciona, en otro post mas adelante veremos como implementarlo con un ejemplo.

 

tombstoninglifecycle

 

  • Page State: Contiene el estado visual de la pagina, utiliza los eventos OnNavigateTo y OnNavigateFrom
  • Application state: Estado de la aplicación, se gestiona a través de la clase PhoneApplicationService 
  • Launcher & Chooser: Son todas aquellas aplicaciones que vienen con el telefono, como llamadas, mensajes, camara y que nuestra aplicación podra invocar. Las estudiaremos con dettalle mas adelante

Aquí tenéis un diagrama en el que se muestra perfectamente el ciclo de vida de una aplicación Windows Phone. Es importante entenderlo para que sepamos como se va a comportar nuestra aplicación, creo que el diagrama de abajo es suficientemente explicativo.

Ff817008.5e84773d-ae0d-43b8-a956-ffdac77b2922(en-us,VS.92).png

Windows Phone–Tutorial II–Orientación

En esta segunda entrada vamos a ver como la posibilidad que nos da de rotar el teléfono influye en el diseño de nuestras aplicaciones. Cuando creamos una aplicación para Windows Phone todas las paginas que creamos podemos controlar desde Xaml si esa pagina puede rotar o no a partir de las propiedades SupportedOrientations y Orientation.

  • SupportedOrientations: define el tipo de orientaciones que la pagina soporta y puede coger los valores de la enumeración SupportedPageOrientation que son: Portrait, Landscape y PortraitOrLandscape.
  • Orientation: contiene la orientación que tiene actualmente la pagina

Para ver como funciona vamos a crear una aplicación sencillita que contiene una imagen., el Xaml seria tan sencillo como

Captura1_thumb1

1 <Grid x:Name="LayoutRoot" Background="Transparent"> 2 <Grid.RowDefinitions> 3 <RowDefinition Height="Auto"/> 4 <RowDefinition Height="*"/> 5 </Grid.RowDefinitions> 6 7 <!--TitlePanel contains the name of the application and page title--> 8 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> 9 <TextBlock x:Name="ApplicationTitle" Text="Orientación" Style="{StaticResource PhoneTextNormalStyle}"/> 10 <TextBlock x:Name="PageTitle" Text="Portrait" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> 11 </StackPanel> 12 13 <!--ContentPanel - place additional content here--> 14 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 15 <Image x:Name="imgPenguins" Source="ImagePenguins.jpg" Stretch="Uniform" ></Image> 16 </Grid> 17 </Grid>

Si ejecutamos la aplicación veremos en el emulador

 

Captura2_thumb1

 

Y ahora como giro el emulador, la pantalla del portátil no puedo girar. El emulador nos ofrece una barra de herramientas (recuadro en rojo) , donde los botones

Captura3_thumb

nos permiten girar el emulador, si los pulsamos veremos como nos queda la aplicación

 

Captura4_thumb

Si nos fijamos la imagen no ocupa toda la pantalla y deberíamos ser capaces de ofrecer una aplicación que se adapte a todos los movimientos del usuario, para detectar los cambios de orientación que realiza el usuario, esto lo podemos ver mejor si en vez de la imagen ponemos un StackPanel con botones.

1 <StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 2 <Button x:Name="btnOne" Content="One"></Button> 3 <Button x:Name="btnTwo" Content="Two"></Button> 4 <Button x:Name="btnThree" Content="Three"></Button> 5 <Button x:Name="btnFour" Content="Four"></Button> 6 <Button x:Name="btnFive" Content="Five"></Button> 7 <Button x:Name="btnSix" Content="Six"></Button> 8 <Button x:Name="btnSeven" Content="Seven"></Button> 9 </StackPanel>

Si lo ejecutamos.

 

Captura5_thumb1Captura6_thumb1

Vemos que cuando giramos perdemos botones con lo que nos damos cuenta que tenemos que introducir un Scroll para que el usuario pueda acceder a todos los botones.

1 <ScrollViewer Grid.Row="1" Margin="12,0,12,83"> 2 <StackPanel x:Name="ContentPanel" > 3 <Button x:Name="btnOne" Content="One"></Button> 4 <Button x:Name="btnTwo" Content="Two"></Button> 5 <Button x:Name="btnThree" Content="Three"></Button> 6 <Button x:Name="btnFour" Content="Four"></Button> 7 <Button x:Name="btnFive" Content="Five"></Button> 8 <Button x:Name="btnSix" Content="Six"></Button> 9 <Button x:Name="btnSeven" Content="Seven"></Button> 10 </StackPanel> 11 </ScrollViewer>

Si ejecutamos y giramos veremos que tampoco nos vale ya que el Scrollviewer no aparecerá debido a que el tamaño del scrollviewer no cambia a la hora de girar.

 

Captura7_thumb1

 

Por lo que debemos de detectar cuando el usuario rotar el teléfono y cambiar el tamaño del Scrollviewer adaptándolo a la posición que tenga el teléfono. Para detectar los giros del teléfono utilizaremos el evento OrientationChanged

1 public MainPage() 2 { 3 InitializeComponent(); 4 OrientationChanged += new EventHandler<OrientationChangedEventArgs>(MainPage_OrientationChanged); 5 } 6 7 void MainPage_OrientationChanged(object sender, OrientationChangedEventArgs e) 8 { 9 if (e.Orientation.Equals(PageOrientation.LandscapeLeft) || 10 e.Orientation.Equals(PageOrientation.LandscapeRight)) 11 { 12 PageTitle.Text = "Landscape"; 13 scContent.Height = 300; 14 } 15 else 16 { 17 PageTitle.Text = "Portrait"; 18 scContent.Height = 500; 19 } 20 }

Ahora aparecerá un Scroll pero este funciona como en el iPhone solo aparece cuando se arrastra el ratón mientras esta pulsado el botón izquierdo, así que no 
esperéis verlo al girar el emulador, tenéis que forzar su visualización
Captura8_thumb1

Os dejo el código

Download File – Orientation

Windows Phone–Tutorial I

Esta es la primera entrada del tutorial de Windows Phone que estoy haciendo según voy aprendiendo esta tecnología, no es del todo cierto porque ya he escrito los artículos anteriores sobre MVVM

 

Voy a suponer que se sabe ya Silverlight que es la tecnología de desarrollo de Windows Phone y vamos a basarnos en las caracteristicas nuevas que tenemos que tener en cuenta.

Si abrimos VS2010 y seleccionamos la opción Silverlight for Windows Phone se nos va a presentar los templates sobre Windows Phone

 

image

Para nuestro primer Hola Mundo vamos a elegir el template Windows Phone Application que nos crea un proyecto basico de WP7 con los siguientes elementos

image

Tenemos los tipicos elementos de cualquier proyecto Silverlight como el App.xaml/cs y MainPage.xaml/cs pero aparecen nuevos elementos

 

  • ApplicationIcon.png: Hace referencia al icono de la aplicación  que se va a mostrar en el telefono.
  • Backgroung.png: Es la imagen que va ha hacer de background en nuestra aplicación
  • WMAppManifest.xml: Fichero de manifiesto que incluye referencia a metadatos a la aplicación como por ejemeplo el fichero que va ha hacer de background, el fichero que contiene el icono, el titulo de la aplicación…

Si abrimos el fichero MainWindow.xaml vamos a ver que nuestra ventana de diseño en VS2010 es diferente a la aplicaciones Silverlight, en la que en el diseño de la ventana tenemos la figura del teléfono

 

image

El editor podéis ver que está dividido en dos mitades en una se muestra el código XAML y en la otra el aspecto final de la página.

Podemos cambiar los textblock de MyApplication y Page Name para poner nuestro Hola Mundo

image

 

Ejecutamos y tenemos nuestra primera aplicación.

Windows Phone – MVVM IV

En el anterior articulo vimos el hola mundo del MVVM con el framework  MVVM Light Toolkit, en este vamos a fijarnos en la clase Messenger que viene en este FrameWork. Esta clase usa un simple modelo publicador/suscriptor (similar al EventAggregator de PRISM, pero de uso más sencillo)  para la transmisión mensajes sin establecer fuertes dependencias entre los comunicados. Los que desean recibir mensajes usan el método Register, y los que desean enviar mensajes usan Send, de esta manera se pueden comunicar componentes pero de forma desacoplada sin que ninguno conozca la existencia del otro.

Para realizar el ejemplo nos vamos a basar en el anterior solo que vamos a añadir una ventana nueva que se invocara desde la ventana principal y que solo tendrá un texbox para que el usuario introduzca un nuevo elemento en el combobox. Os adjuntare el código para que lo estudiéis ya que va a ser un poco complicado explicarme.

Añadimos al proyecto una nueva vista denominada SecondWindow junto con su ViewModel, recordar, utilizar el template que nos proporciona MVVM Light Toolkit

 

image

 

En nuestro caso lo denominamos MvvmViewModelSecondWindow, siempre que creamos un nuevo ViewModel debemos de añadirlo a la clase ViewModelLocator del proyecto aprovechando el snippet que nos proporciona el framework o a mano, en este caso lo vamos a escribir a mano para que se afiancen conceptos.

Nos debería quedar de la siguiente forma

1 public class ViewModelLocator 2 { 3 private static MainViewModel _main; 4 private static MvvmViewModelSecondWindow _second; 5 6 7 /// <summary> 8 /// Initializes a new instance of the ViewModelLocator class. 9 /// </summary> 10 public ViewModelLocator() 11 { 12 ////if (ViewModelBase.IsInDesignModeStatic) 13 ////{ 14 //// // Create design time view models 15 ////} 16 ////else 17 ////{ 18 //// // Create run time view models 19 ////} 20 21 CreateMain(); 22 23 } 24 25 /// <summary> 26 /// Gets the Main property. 27 /// </summary> 28 public static MainViewModel MainStatic 29 { 30 get 31 { 32 if (_main == null) 33 { 34 CreateMain(); 35 } 36 37 return _main; 38 } 39 } 40 41 42 /// <summary> 43 /// Gets the Main property. 44 /// </summary> 45 public static MvvmViewModelSecondWindow SecondStatic 46 { 47 get 48 { 49 if (_second == null) 50 { 51 CreateSecond(); 52 } 53 54 return _second; 55 } 56 } 57 58 /// <summary> 59 /// Gets the Main property. 60 /// </summary> 61 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", 62 "CA1822:MarkMembersAsStatic", 63 Justification = "This non-static member is needed for data binding purposes.")] 64 public MainViewModel Main 65 { 66 get 67 { 68 return MainStatic; 69 } 70 } 71 72 /// <summary> 73 /// Gets the Main property. 74 /// </summary> 75 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", 76 "CA1822:MarkMembersAsStatic", 77 Justification = "This non-static member is needed for data binding purposes.")] 78 public MvvmViewModelSecondWindow Second 79 { 80 get 81 { 82 return SecondStatic; 83 } 84 } 85 86 /// <summary> 87 /// Provides a deterministic way to delete the Main property. 88 /// </summary> 89 public static void ClearMain() 90 { 91 _main.Cleanup(); 92 _main = null; 93 } 94 95 /// <summary> 96 /// Provides a deterministic way to delete the Main property. 97 /// </summary> 98 public static void ClearSecond() 99 { 100 _second.Cleanup(); 101 _second = null; 102 } 103 104 /// <summary> 105 /// Provides a deterministic way to create the Main property. 106 /// </summary> 107 public static void CreateMain() 108 { 109 if (_main == null) 110 { 111 _main = new MainViewModel(); 112 } 113 } 114 115 /// <summary> 116 /// Provides a deterministic way to create the Main property. 117 /// </summary> 118 public static void CreateSecond() 119 { 120 if (_second == null) 121 { 122 _second = new MvvmViewModelSecondWindow(); 123 } 124 } 125 126 /// <summary> 127 /// Cleans up all the resources. 128 /// </summary> 129 public static void Cleanup() 130 { 131 ClearMain(); 132 ClearSecond(); 133 } 134 }

Una vez introducido nuestro nuevo ViewModel en la clase ViewModelLocator, vamos a cambia la vista principal para añadirle un nuevo botón que nos permita abrir nuestra segunda vista

 

image

 

Para utilizar ese botón debemos crear un RelayCommand tal y como vimos en el anterior articulo

1 2 3 /// <summary> 4 /// Initializes a new instance of the MainViewModel class. 5 /// </summary> 6 public MainViewModel() 7 { 8 if (IsInDesignMode) 9 { 10 // Code runs in Blend --> create design time data. 11 } 12 else 13 { 14 _newItem = string.Empty; 15 Items = new ObservableCollection<ModelTest>(); 16 AddItemCommand = new RelayCommand(AddItem, CanAddNewItem); 17 AddItemNewWindowCommand = new RelayCommand(AddItemNewWindow); 18 } 19 } 20 21 private void AddItemNewWindow() 22 { 23 SecondWindow secondWindow = new SecondWindow(); 24 secondWindow.ShowDialog(); 25 26 } 27 ............

Y enlazamos el nuevo botón con su comando

 

1 <Button Command="{Binding AddItemNewWindowCommand}" Content="Insertar Nueva Ventana" Height="21" HorizontalAlignment="Left" Margin="115,67,0,0" Name="btnNewWindow" VerticalAlignment="Top" Width="138" />

Ahora deberíamos probar y comprobar que se nos abre la nueva ventana y en efecto así es. Nos falta ahora diseñar la nueva vista

 

 

image

 

Ahora nos metemos con su ViewModel, recordar que no debemos de tocar la vista (luego veremos que sera necesario), creamos el comando de Insertar Nuevo Item

Este ViewModel va a ser muy parecido al de MainWindow va a tener las propiedades NewItem, Items y el RelayCommand AddItemCommand lo que tenemos que hacer es que la clase Items contenga los items de la ventana MainWindow y que la devuelva con los items que haya insertado en la SecondWindow, pero todo ello sin que se conozcan las vistas. Para ello utilizaremos la clase Messenger.

En la clase MainWindowViewModel donde llamamos a la nueva vista utilizamos el metodo Send para enviar el mensaje con la variable Items . El método Send es tan sencillo como

 

void Send<T>(T message);

Así que podría ser 

Messenger.Default.Send(Items);

El problema es que este mensaje llegaria a todos los que registren un mensaje que les van a enviar de tipo ObbservableCollection<Model> que es el tipo de Items, para acotar a la viewmodel a la que queremos enviar utilizamos

void Send<TMessage, TTarget>(TMessage message);

En nuestro caso

1 private void AddItem() 2 { 3 ModelTest newItem = new ModelTest(); 4 newItem.Code = Items.Count == 0 ? 1 : Items[Items.Count - 1].Code + 1; 5 newItem.Description = NewItem; 6 7 Items.Add(newItem); 8 Messenger.Default.Send<ObservableCollection<ModelTest>, MvvmViewModelSecondWindow>(Items); 9 10 11 }

 

Nos queda ver como recibir ese mensaje, para ello primero lo registramos en la ViewModel MvvmViewModelSecondWindow en su constructor

 

1 public MvvmViewModelSecondWindow() 2 { 3 if (IsInDesignMode) 4 { 5 // Code runs in Blend --> create design time data. 6 } 7 else 8 { 9 _newItem = string.Empty; 10 11 AddItemCommand = new RelayCommand(AddItem); 12 Messenger.Default.Register<ObservableCollection<ModelTest>>( 13 this, 14 Lista => Items = Lista); 15 16 } 17 18 19 }

En el registro del mensaje indicamos su contenedor en este caso la propia clase y una acción a realizar con el parámetro que nos envía el mensaje, de esta manera ya tenemos la propiedad Items con los valores de la clase MainWindowViewModel. Para enviar el nuevo item no haremos nada ya que la propiedad se pasa por referencia entre las ViewModel con lo que el combo se actualiza automáticamente

Solo nos queda cerrar la Vista, esto no se puede hacer desde la ViewModel, para ello tendremos que codificar el code-behind de la vista poniendo el evento click en el botón de insertar ejecutando el método Close para que se cierre la vista

Código

Download File – MVVMMessenger

Windows Phone – MVVM III

Una vez visto en el articulo anterior una breve entrada de un ejemplo del patrón MVVM vamos a ver ahora utilizando el framework MVVM Light Toolkit, una vez que instalamos el framework veremos que a la hora de crear un nuevo proyecto de WPF o Silverlight o Windows Phone tendremos nuevas opciones, en WPF podemos ver las entradas

image

Nosotros vamos a elegir MvvmLight (WPF 4) y vemos que nos va a generar ya una estructura de proyecto con unas clases determinadas

 

image

Una clase que aparece nueva con respecto a lo que vimos en el anterior articulo es la clase ViewModelLocator es el encargado de instanciar y mantener una referencia de cada ViewModel que existe en nuestra aplicación, si la abrimos veremos que contiene una propiedad Main haciendo referencia a MainViewModel además de manera estática

1 /// <summary> 2 /// Gets the Main property. 3 /// </summary> 4 public static MainViewModel MainStatic 5 { 6 get 7 { 8 if (_main == null) 9 { 10 CreateMain(); 11 } 12 13 return _main; 14 } 15 } 16 17 /// <summary> 18 /// Gets the Main property. 19 /// </summary> 20 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", 21 "CA1822:MarkMembersAsStatic", 22 Justification = "This non-static member is needed for data binding purposes.")] 23 public MainViewModel Main 24 { 25 get 26 { 27 return MainStatic; 28 } 29 }

Si añadimos nuestro modelo veremos que aparecen nuevas opciones para añadir nuevos elementos al proyecto

image

 

Para nuestro modelo utilizaremos la típica clase de cualquier proyecto y crearemos el mismo modelo que nuestro anterior articulo ya que vamos a realizar el mismo ejemplo. Nuestra vista va a ser igual al del ejemplo anterior solo que en este caso hay una pequeña diferencia en el DataContext, primero que ya viene en el template de MVVMLight y que hace referencia a la clase ViewModelLocator

 DataContext="{Binding Main, Source={StaticResource Locator}}"

 

Si vemos la clase ViewModel que nos ha generado vemos que deriva de la clase ViewModelBase que proporciona ciertos elementos que nos ayudaran en nuestro desarrollo en MVVM.Por ejemplo ViewModelBase implementa ya el INotifyPropertyChanged y además nos provee de un método en el cual podemos hacer limpieza en caso de que sea necesaria, también nos ofrece la propiedad IsInDesignMode que indica si estamos en diseño o no.

Podríamos copiar toda nuestra anterior ViewModel pero no vamos a copiar la propiedad AddItemCommand ya que RelayCommand en este caso viene proporcionado por el FrameWork y la declararemos con la siguiente línea

Luego en el constructor enlazamos los métodos para ejecutar la acción y el que comprueba si se puede ejecutar, en nuestro caso

AddItemCommand = new RelayCommand(AddItem,CanAddNewItem);


Ya tendríamos completado nuestro ejemplo anterior, de manera que nuestra ViewModel quedaría de la siguiente manera

 

1 public class MainViewModel : ViewModelBase 2 { 3 #region Private members 4 5 private string _newItem; 6 7 private ModelTest _selectedItem; 8 9 #endregion 10 11 public string NewItem 12 { 13 get 14 { 15 return _newItem; 16 } 17 18 set 19 { 20 _newItem = value; 21 RaisePropertyChanged("NewItem"); 22 } 23 } 24 25 26 public ModelTest SelectedItem 27 { 28 get 29 { 30 return _selectedItem; 31 } 32 set 33 { 34 _selectedItem = value; 35 RaisePropertyChanged("SelectedItem"); 36 } 37 } 38 39 40 public ObservableCollection<ModelTest> Items { get; set; } 41 42 public RelayCommand AddItemCommand { get; private set; } 43 44 /// <summary> 45 /// Initializes a new instance of the MainViewModel class. 46 /// </summary> 47 public MainViewModel() 48 { 49 if (IsInDesignMode) 50 { 51 // Code runs in Blend --> create design time data. 52 } 53 else 54 { 55 _newItem = string.Empty; 56 Items = new ObservableCollection<ModelTest>(); 57 AddItemCommand = new RelayCommand(AddItem, CanAddNewItem); 58 } 59 } 60 61 62 private void AddItem() 63 { 64 ModelTest newItem = new ModelTest(); 65 newItem.Code = Items.Count == 0 ? 1 : Items[Items.Count - 1].Code + 1; 66 newItem.Description = NewItem; 67 SelectedItem = newItem; 68 69 Items.Add(newItem); 70 71 } 72 73 private bool CanAddNewItem() 74 { 75 return NewItem.Length > 5; 76 } 77 78 }

Os dejo el código para que le echéis un vistazo, en el próximo articulo veremos la característica Messenger de MVVMLight

 

Download File – MVVMLight

Windows Phone – MVVM II

En el anterior articulo comenzamos con una mini introducción de MVVM explicando conceptos e indicando que iba a poner ejemplos utilizando el framwork MVVM Light Toolkit, pero antes de empezar con MVVM Light Toolkit voy a realizar un “Hola Mundo” sin ningún framework, el ejemplo va a ser sencillo un TextBox un botón y un combo y la idea es que cuando de al botón lo escrito en el TextBox se añada como item al combobox.

 

Lo primero que tenemos que tener en cuenta que a la hora de crear la estructura del proyecto se recomienda tener una carpeta por cada elemento del patrón, es decir, una para los modelos, otra para las vistas y la ultima para las viewmodels

 

image

Donde en las vistas como hemos dichos tendremos nuestro código XAML y las demás serán clases.

 

Si empezamos por el modelo, aquí tendremos solo una clase con dos propiedades el código del item a insertar en el combo y su descripción que sera la introducida por el usuario. En esta clase estarían todos los accesos a recuperar datos, persistir… de este modelo se llamaría a los servicios web del negocio de este modelo, en este caso no tenemos ninguno.

 

1 namespace HelloWorldMVVM.Models 2 { 3 class Model 4 { 5 public int Code { get; set; } 6 public string Description { get; set; } 7 8 } 9 }

La vista es muy sencilla

 

image

 

Debemos de recordar que el cs del XAML tiene que estar vacio y en nuestro caso debe de ser así.

Si nos centramos ahora en la VistaModelo vamos a crear una nueva clase denominada RelayCommand, esta clase implementara la interfaz ICommand que ya hemos visto en el articulo Commands en WPF, con esta clase definiremos un mecanismo que nos permitirá definir un método que se ejecutara cuando se invoque el comando y aprovechando el método CanExecuteChanged tendremos otro método que nos indicará si el comando se puede lanzar, por ejemplo nosotros vamos a poner que no se puede añadir si el texto introducido no tiene como mínimo 5 caracteres. Esta clase es típica en todos los desarrollos de MVVM

 

1 public class RelayCommand : ICommand 2 { 3 public Predicate<object> CanExecuteDelegate; 4 public Action<object> ExecuteDelegate; 5 6 public bool CanExecute(object parameter) 7 { 8 return CanExecuteDelegate(parameter); 9 } 10 11 public event EventHandler CanExecuteChanged 12 { 13 add { CommandManager.RequerySuggested += value; } 14 remove { CommandManager.RequerySuggested -= value; } 15 } 16 17 public void Execute(object parameter) 18 { 19 ExecuteDelegate(parameter); 20 } 21 }

Esta clase es la que utilizaremos en la creación de los comandos en todas las vistas que veremos mas adelante.

Lo primero es definir en la vista la vista-modelo que va a utilizar y todo ello por XAML aprovechando las características de DataBinding, la manera de hacerlo es muy sencilla

1 <Window x:Class="HelloWorldMVVM.Views.HelloWorldWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:vm="clr-namespace:HelloWorldMVVM.ViewModels" 5 Title="HelloWorldWindow" Height="300" Width="300"> 6 <Window.DataContext> 7 <vm:ViewModel/> 8 </Window.DataContext>

 

Tal y como podéis ver en el código a través de la línea xmlns:vm="clr-namespace:HelloWorldMVVM.ViewModels" hacemos referencia a todas las clase que cuelguen del namespace HelloWorldMVVM.ViewModels y en la propiedad DataContext seleccionamos la clase ViewModel que queremos utilizar. Como utilizamos DataBinding debemos recordar que tenemos que implementar la interfaz INotifyPropertyChanged una vez implementada vamos a definir una propiedad que serán los items del combobox de tipo ObservableCollection de nuestro Model y una propiedad para el texto del nuevo item

 

En esta clase nos quedaría una ultima propiedad que será el comando enlazado con el botón utilizando la clase RelayCommand

 

1 #region Properties 2 3 public string NewItem 4 { 5 get 6 { 7 return _newItem; 8 } 9 10 set 11 { 12 _newItem = value; 13 NotifyPropertyChanged("NewItem"); 14 } 15 } 16 17 18 public Model SelectedItem 19 { 20 get 21 { 22 return _selectedItem; 23 } 24 set 25 { 26 _selectedItem = value; 27 NotifyPropertyChanged("SelectedItem"); 28 } 29 } 30 31 32 public ObservableCollection<Model> Items { get; set; } 33 34 35 #region AddItemCommand 36 37 public ICommand AddItemCommand 38 { 39 get 40 { 41 this._AddItemCommand = new RelayCommand() 42 { 43 CanExecuteDelegate = p => CanAddNewItem(), 44 ExecuteDelegate = p => AddItem() 45 }; 46 return this._AddItemCommand; 47 } 48 } 49 50 private void AddItem() 51 { 52 Model newItem = new Model(); 53 newItem.Code = Items.Count == 0 ? 1 : Items[Items.Count - 1].Code + 1; 54 newItem.Description = NewItem; 55 SelectedItem = newItem; 56 57 Items.Add(newItem); 58 59 } 60 61 private bool CanAddNewItem() 62 { 63 return NewItem.Length > 5; 64 } 65 66 #endregion 67 68 #endregion

Debemos fijarnos como hemos creado la propiedad AddItemCommand derivada de ICommand utilizando la clase RelayComand para enlazar los métodos CanAddNewItem y AddItem.

 

Ahora vamos a enlazar todo en la vista a través del Binding

1 <Window x:Class="HelloWorldMVVM.Views.HelloWorldWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:vm="clr-namespace:HelloWorldMVVM.ViewModels" 5 Title="HelloWorldWindow" Height="300" Width="300"> 6 <Window.DataContext> 7 <vm:ViewModel/> 8 </Window.DataContext> 9 <Grid> 10 <TextBlock Height="23" HorizontalAlignment="Left" Margin="16,23,0,0" Name="textBlock1" Text="Introduce el texto a insertar:" VerticalAlignment="Top" /> 11 <TextBox Height="24" Text="{Binding Path=NewItem, Mode=TwoWay}" HorizontalAlignment="Left" Margin="175,20,0,0" Name="txtTextToÏnsert" VerticalAlignment="Top" Width="91" /> 12 <Button Content="Insertar" Command="{Binding AddItemCommand}" Height="21" HorizontalAlignment="Left" Margin="80,67,0,0" Name="btnAdd" VerticalAlignment="Top" Width="80" /> 13 <TextBlock Height="18" HorizontalAlignment="Left" Margin="16,122,0,0" Name="textBlock2" Text="Items:" VerticalAlignment="Top" Width="53" /> 14 <ComboBox Height="20" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" DisplayMemberPath="Description" HorizontalAlignment="Left" Margin="66,122,0,0" Name="cboItems" VerticalAlignment="Top" Width="187" /> 15 </Grid> 16 </Window>

El comando lo enlazamos al botón el TextBlock a la propiedad NewItem,la propiedad Items al Combo.

 

Tenéis el código para descargarlo y ver mejor la implementación que es un poco complicada de seguir

Download File – HelloWorldMVVM

Windows Phone – MVVM I

Dentro de la serie de Windows Phone el otro día vimos como instalar las herramientas para su desarrollo, pero antes de empezar a meternos en harina lo primero que tenemos que aprender es a desarrollar con el patrón MVVM que si desarrolláis en WPF o Silverlight es el que se recomienda que utilizar y como el desarrollo de Windows Phone 7 se hace en Silverlight es importante aprenderlo. el patrón MVVM tiene una serie de ventajas, también sus desventajas que hace que sea el mas lógico a la hora de realizar desarrollos en esta tecnología

Ventajas

  • Desacople de la vista y la lógica de la aplicación.
  • Testeabilidad.
  • Desarrollar Múltiples UI sin un coste excesivo 

Desventajas

  • Falta de estandarización.
  • Para interfaces de usuario sencillas MVVM puede ser excesivo.
  • Curva de aprendizaje.

Este patrón puede implementarse de manera fácil en SL/WPF gracias a las características de DataBinding que incorporan se compone de 3 capas perfectamente diferenciadas

 

  • El modelo (Model).  El modelo es responsable de todos los datos de la aplicación y de la lógica de negocios relacionada.
  • La vista (View) o vistas. Una o más representaciones para el usuario final del modelo de la aplicación. La vista es responsable de mostrar los datos al usuario y de permitir la manipulación de los datos de la aplicación, es decir, la pantalla y solo tiene eso “pintura” nada mas
  • El modelo-vista(ViewModel). Uno o más por vista. El modelo-vista es responsable de implementar el comportamiento de la vista para responder a las acciones del usuario y de exponer los datos del modelo de forma tal que sea fácil usar bindings en la vista.

Este patrón puede implementarse a mano, yo utilizo un Framework el cual he ido observando desde el principio y realmente creo que ayuda y esta maduro para su utilización, este framework es el MVVM Light Toolkit. teniendo versiones tanto para WPF, Silverlight y Windows Phone (nuestro tema) ayudando a implementar este patrón de forma sencilla.

Este “toolkit” esta realizado por Laurent Bugnion y en el ultimo Mix realizo una charla bastante interesante de el. En los siguientes posts nos dedicaremos a este “Toolkit”. Si queréis aquí hay algunos enlaces interesantes

 

Windows Phone el comienzo

Hola, ya sabéis todo el mundo que hace poco se lanzo ya el primer terminal de Windows Phone con muchísima expectación por parte de todo el mundo. Como poseedor de un iPhone desde hace tiempo estaba un poco escéptico del éxito que tendría, consideraba que llegaba tarde al mercado, después de tenerlo en mis manos, solo durante unos minutos, me parece un terminal que si puede triunfar en el mundo de los móviles.

Lo que me da una excusa (aunque lo que me conocéis lo de aprender tecnología nueva es un hobby ) para aprender a desarrollar sobre esta nueva tecnología, aprovechando mis pocos conocimientos de Silverlight y WPF.

He decidido que ya que voy a aprender voy a intentar plasmar los temas que voy a ir adquiriendo poco a poco y lo primero que vamos a ver es que necesitamos para desarrollar en Windows Phone. Microsoft a decidido que no necesitamos gastarnos ni un duro para que podamos desarrollar para su teléfono solo necesitamos ir a http://developer.windowsphone.com y nos encontramos con la pagina

 

image

 

En esta pagina vemos claramente el enlace para descargarnos todo lo que necesitamos. Pinchando sobre el nos lleva a la pagina de descarga

 

image

 

En esta pagina descargaremos el archivo vm_web.exe que nos realizara la instalación. Una vez instalada podremos empezar a desarrollar en Windows Phone.

 

La primera sencillita.

MEF y RequiredCreationPolicy

En el anterior articulo vimos la recomposición y como aunque recargásemos los plugins con la opción Refresh se seguían manteniendo las instancias(lo comprobábamos con la propiedad NumCall) . Esto es debido a que sino especificamos nada las instancias de los plugins se crean con el patrón Singleton , es decir, una única instancia siempre. Este modelo de creación lo podemos cambiar con un atributo este es RequiredCreationPolicy el cual nos permite indicar el modelo de creación de nuestros plugins.

Este atributo es una enumeración con tres elementos

  • Shared: Especifica que solo va a existir una instancia (Singleton)
  • NonShared: Cada vez se creara una instancia del plugin
  • Any: Es por defecto y el importador decide cual es la política mejor entre las dos anteriores.

Si quisiéramos que cada vez se generase una instancia el código a modificar sería

 

1 [ImportMany(typeof(HelloWorldContract),AllowRecomposition=true,RequiredCreationPolicy= CreationPolicy.NonShared)] 2 private ObservableCollection<HelloWorldContract> pluginsHello = new ObservableCollection<HelloWorldContract>();

De esta manera cuando demos al botón “Añadir Plugin” y detecte uno nuevo creara nuevas instancias reiniciando la propiedad NumCall. Este atributo es importante para que decidamos como queremos que se comporten los plugins. Además este atributo lo podemos poner a la hora de importar o exportar, es decir, en el propio plugin pero esta vez con el atributo PartCreationPolicy

1 [PartCreationPolicy(CreationPolicy.NonShared)] 2 [Export(typeof(HelloWorldContract))] 3 public class HolaMundo :HelloWorldContract 4 { 5

 

 

 

MEF y la Recomposición

En el anterior articulo vimos el hola mundo de MEF, en este articulo vamos a tratar la recomposición y con esto nos referimos a que MEF nos permite añadir plugins en tiempo de ejecución sin tener que reiniciar nuestro programa.

Para nuestro ejemplo he cambiado un poco el código anterior, he añadido al contrato la propiedad NumCall con la que cada vez que se ejecute el método Hello se mostrará un mensaje con Hola en el idioma seleccionado y el número de veces que lo vamos llamando.

Además he añadido en la ventana un botón de Añadir Plugin que simulara que nos bajamos de internet un plugin nuevo y lo cargamos, la bajada la haremos a a mano copiando en el directorio pugins un nuevo plugin HelloWorldEuskera antes de pulsar el botón. La pantalla quedaría de esta forma.

 

image

 

Para realizar la carga de nuevo plugins MEF nos proporciona el método Refresh en la clase DirectoryCatalog, de manera que el botón “Añadir Plugin” tendría el código.

1 void btnAdd_Click(object sender, RoutedEventArgs e) 2 { 3 //Refrescamos el catalogo para ver si hay mas plugins en el directorio 4 catalog.Refresh(); 5 6 }

 

Si lo ejecutamos y una vez ejecutado copiamos el nuevo plugin y damos al botón “Añadir Plugin” se nos producirá la excepción

 

image

Esto es debido a que no hemos puesto el atributo AllowRecomposition

1 [ImportMany(typeof(HelloWorldContract),AllowRecomposition=true)] 2 private ObservableCollection<HelloWorldContract> pluginsHello = new ObservableCollection<HelloWorldContract>();

Con este atributo nos va a permitir cargar nuevos plugins en tiempo de ejecución y podremos comprobar con la propiedad NumCall  que aunque carguemos nuevos plugins en la colección no se crean nuevas instancias manteniendo los valores de las propiedades.

 

Download File – Código