Windows Phone–Tutorial – Navegación con MVVM Light Toolkit

En el anterior articulo vimos como se podía realizar la navegación entre páginas en un wp7, en el comienzo del tutorial hicimos hincapié en la necesidad de utilizar el patrón MVVM para nuestros desarrollo  y que yo me había decidido por utilizar el framework  MVVM Light Toolkit. En esta entrada implementaremos la navegación entre páginas utilizando MVVM, para ello primero recomiendo leer las entradas:

Una vez que hemos refrescado nuestros conocimientos vamos a crear nuestro proyecto utilizando el template proporcionado por el framework

 

image

Al crear el proyecto nos aparece el mensaje

image

Esto quiere decir que no hemos instalado el hotfix http://blog.galasoft.ch/archive/2010/07/22/mvvm-light-hotfix-for-windows-phone-7-developer-tools-beta.aspx , una vez instalado el mensaje desaparece.

Al crear el proyecto nos lo genera con la siguiente estructura

image

 

Si añadimos la segunda pagina utilizamos el template de view y el de viewModel

 

imageimage

Debemos recordar primero asignar al DataContext de la nueva view el viewmodel que creemos y que por cada ViewModel que creemos debemos de añadirlo al Locator, tal y como vimos en los artículos sobre MVVM.

Si os fijáis en la pagina que nos crea ya viene el titulo de la aplicación y de la página “bindeados” a la viewnodel, tal y como debe ser

1 <StackPanel x:Name="TitlePanel" 2 Grid.Row="0" 3 Margin="24,24,0,12"> 4 <TextBlock x:Name="ApplicationTitle" 5 Text="{Binding ApplicationTitle}" 6 Style="{StaticResource PhoneTextNormalStyle}" /> 7 <TextBlock x:Name="PageTitle" 8 Text="{Binding PageName}" 9 Margin="-3,-8,0,0" 10 Style="{StaticResource PhoneTextTitle1Style}" /> 11 </StackPanel>

Lo que tenemos que hacer ahora es modificar la viewmodel para añadir un RelayComand en nuestro caso le llamaremos NavigatePage2Command y enlazarlo al botón como hacíamos con Command en los ejemplos realizados en los anteriores artículos, pero nos encontraremos con el error

The property ‘Command’ was not found in type ‘Button’.  

Ya que Command no existe en WP7, para que se lance nuestro comando debemos de hacer uso de una clase que nos ofrece el Framework que es EventToComand, esta clase la usaremos para realizar binding entre un evento y un comando directamente en XAML. Para ello debemos añadir nuevos nameespaces a la página

               xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
               xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7"
            

Estos namespaces corresponde el primero al que nos proporciona la posibilidad de utilizar triggers y el segundo es el que nos ofrece EventToCommand, una vez añadidos, el XAML nos quedaría

1 <!--ContentPanel - place additional content here--> 2 <Grid x:Name="ContentGrid" 3 Grid.Row="1"> 4 5 <TextBox Text="{Binding UserText}" Height="74" HorizontalAlignment="Left" Margin="26,41,0,0" Name="txtText" VerticalAlignment="Top" Width="398" /> 6 <Button Content="Siguiente Página" Height="82" HorizontalAlignment="Left" Margin="88,143,0,0" Name="btnNext" VerticalAlignment="Top" Width="259" > 7 <i:Interaction.Triggers> 8 <i:EventTrigger EventName="Click"> 9 <cmd:EventToCommand Command="{Binding NavigatePage2Command}" /> 10 </i:EventTrigger> 11 </i:Interaction.Triggers> 12 </Button> 13 14 </Grid> 15

 

De esta manera invocamos al comando cuando el usuario pulse el botón, en la viewmodel declarariamos el RelayCommand y lanzaríamos el mensaje.

1 public MainViewModel() 2 { 3 if (IsInDesignMode) 4 { 5 // Code runs in Blend --> create design time data. 6 } 7 else 8 { 9 _userText = string.Empty; 10 NavigatePage2Command = new RelayCommand(NavigatePage2); 11 12 // Code runs "for real" 13 } 14 } 15 16 17 private void NavigatePage2() 18 { 19 Uri navigation = new Uri("/Page2.xaml?text=" + UserText); 20 Messenger.Default.Send<Uri, MainViewModel>(navigation); 21 }

 

En vez de enviar el mensaje podríamos llamar directamente a la página a través de NavegationService, pero haríamos que nuestro ViewModel solo funcionase para Silverlight y WP7 y no para WPF y si queremos ser puros en la implementación del patrón MVVM, en este caso enviamos un mensaje con la Uri a la que queremos navegar. Pero este mensaje quien lo va a recoger? si solo existe la vista MainPage con su ViewModel creada, con lo que nadie va a recoger el mensaje y tratarlo.

Para solventar esto vamos a crear una clase PhoneApplicationPageBase  que derivara de la clase base de las paginas que es PhoneApplicationPage, en esta clase registraremos todos los mensajes comunes a las paginas como en nuestro caso la navegación y los trataremos. Esta clase es muy sencilla

1 public class PhoneApplicationPageBase : PhoneApplicationPage 2 { 3 protected override void OnNavigatedTo(NavigationEventArgs e) 4 { 5 base.OnNavigatedTo(e); 6 RegisterMessages(); 7 } 8 9 protected override void OnNavigatedFrom(NavigationEventArgs e) 10 { 11 base.OnNavigatedFrom(e); 12 UnregisterAll(); 13 } 14 15 internal void RegisterMessages() 16 { 17 RegisterNavigationMessaging(); 18 19 } 20 21 protected void UnregisterAll() 22 { 23 Messenger.Default.Unregister(this); 24 } 25 26 protected void RegisterNavigationMessaging() 27 { 28 Messenger.Default.Register<Uri>(this, "NavigationRequest", Navigate); 29 } 30 31 private void Navigate(Uri uri) 32 { 33 NavigationService.Navigate(uri); 34 } 35 } 36

Si nos fijamos en la clase vemos que en el evento OnNavigateTo registramos los mensajes que queremos tratar y en el evento OnNavigatedFrom los anulamos.

Ahora lo que debemos hacer es que nuestras páginas deriven de esta nueva clase, modificamos el XAML

1 <helper:PhoneApplicationPageBase x:Class="WP7NavigationMVVM.MainPage" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" 5 xmlns:helper="clr-namespace:WP7NavigationMVVM.Helper;assembly=WP7NavigationMVVM" 6 xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" 7 .........

 

Y el code-behind

 public partial class MainPage : PhoneApplicationPageBase

 

Hemos visto que a la hora de enviar la Uri la enviamos con el párametro en QueryString

  private void NavigatePage2()
        {
            Uri navigation = new Uri("/Page2.xaml?text=" + UserText,UriKind.Relative);
            Messenger.Default.Send(navigation, "NavigationRequest");
       
        }

Pero en el mensaje en vez de enviar una Uri, podemos enviar una clase nuestra que tenga una propiedad que sea la uri a navegar y otra propiedad con un diccionario<string,string> con los querystrings que quieres enviar o …. la estrategia que mas os convenga para pasar parámetros de una página a otra.

Lo que yo voy a hacer es extender la clase PhoneApplicationPageBase con un nuevo método CheckQueryStrings, este método comprobara si la viewmodel de la página contiene propiedades igual al nombre de la QueryString, en nuestro caso en la Page2 tengo la propiedad UserText y el querystring le llamo igual de manera que se lo asignare siempre automáticamente evitándome en cada pagina realizarlo ya que este método lo hará por mi.

1 private void CheckQueryStrings() 2 { 3 var count = this.NavigationContext.QueryString.Count; 4 if (0 == count) return; 5 ViewModelBase vm = null; 6 if (DataContext is ViewModelBase) 7 vm = DataContext as ViewModelBase; 8 else return; 9 10 //Por cada query string lo enlazo a su propiedad de la pagina a la que navego 11 foreach (var queryString in NavigationContext.QueryString) 12 { 13 var propInfo = vm.GetType().GetProperty(queryString.Key); 14 if (null != propInfo) 15 { 16 if (propInfo.PropertyType == typeof(string)) 17 propInfo.SetValue(vm, queryString.Value, null); 18 else if (propInfo.PropertyType == typeof(long?) || propInfo.PropertyType == typeof(long)) 19 propInfo.SetValue(vm, Convert.ToInt64(queryString.Value), null); 20 } 21 } 22 23 } 24

 

De esta manera la navegación la tengo centralizada en una sola clase y cumplo a rajatabla el patrón MVVM, os dejo el códig

 

2 comentarios sobre “Windows Phone–Tutorial – Navegación con MVVM Light Toolkit”

Responder a anonymous Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *