[MVVM] Navegación entre Páginas en Windows Phone 8.1 Silverlight

[MVVM] Navegación entre Páginas en Windows Phone 8.1 Silverlight
MVVMNavigationServiceTutorial

¡Hola geeks!

Si alguien sigue con un proyecto entre manos con Windows Phone 8.1 Silverlight, seguro que sabrá su limitación al querer pasar objectos complejos entre ellas. Pues hoy vamos a traeros una solución bastante buena que en su día adquirí gracias a Alex Campos Magencio.

Para que nuestro proyecto adquiera paso de objectos y navegación por tipo (en Silverlight se navega por url) vamos a seguir los siguientes pasos:

1. Creamos un nuevo proyecto con el entorno de Windows Phone 8.1 Silverlight.

No confundiros con el Windows Phone 8.1 a secas que se refieren al entorno que tiene el núcleo RT de Windows 8.1

2. Crear una Interfaz INavigable:

Esta interfaz nos servirá para capturar los objetos pasados por navegación. Tenemos que implementarlo en cada ViewModel y ahí es donde lo igualaremos a nuestras propiedades de dicha vista.

public interface INavigable { /// <summary> /// Sets the navigation context. /// </summary> /// <value> /// The navigation context. /// </value> object NavigationContext { set; } }

3. Crear una Interfaz INavigationService:

Crearemos nuestra interfaz con los métodos a utilizar.

public interface INavigationService { void NavigateTo<TDestinationViewModel>(); void NavigateTo<TDestinationViewModel>(object navigationContext); void NavigateBack(); void NavigateBack(object navigationContext); void ClearNavigationHistory(); }

4. Creamos su implementacion:

Crearemos NavigationService para implementar de nuestro Servicio. Aquí la variable importante es viewModelRouting. En ese diccionario vamos a almacenar los ViewModels y su expresión url para. Los siguientes métodos los iremos implementando a base de la navegación PhoneApplicationFrame.

public class NavigationService : INavigationService { public NavigationService() { } // Correspondencia entre los vista-modelo y sus vistas private static IDictionary<Type, string> viewModelRouting = new Dictionary<Type, string>() { { typeof(MainViewModel), "/MainPage.xaml" }, { typeof(AboutViewModel), "/Views/AboutView.xaml" }, { typeof(ColorPickerViewModel), "/Views/ColorPickerView.xaml" } }; // Parámetros complejos que se pasan a los vista-modelo asociados a las vistas private object navigationContext; // Navega a la vista de un vista-modelo sin paso de parámetros /// <summary> /// Navigates to. /// </summary> /// <typeparam name="TDestinationViewModel">The type of the destination view model.</typeparam> public void NavigateTo<TDestinationViewModel>() { PhoneApplicationFrame rootFrame = Application.Current.RootVisual as PhoneApplicationFrame; rootFrame.Navigate(new Uri(viewModelRouting[typeof(TDestinationViewModel)], UriKind.Relative)); } // Navega a una vista pasándole parámetros complejos a su vista-modelo /// <summary> /// Navigates to. /// </summary> /// <typeparam name="TDestinationViewModel">The type of the destination view model.</typeparam> /// <param name="navigationContext">The navigation context.</param> public void NavigateTo<TDestinationViewModel>(object navigationContext) { // Parámetros para el vista-modelo this.navigationContext = navigationContext; // Navega a la página y entérate de cuándo hemos llegado PhoneApplicationFrame rootFrame = Application.Current.RootVisual as PhoneApplicationFrame; rootFrame.Navigated += new NavigatedEventHandler(Page_Navigated); rootFrame.Navigate(new Uri(viewModelRouting[typeof(TDestinationViewModel)], UriKind.Relative)); } // Navega de vuelta a la vista anterior, sin pasarle parámetros a su vista-modelo /// <summary> /// Navigates the back. /// </summary> public void NavigateBack() { PhoneApplicationFrame rootFrame = Application.Current.RootVisual as PhoneApplicationFrame; if (rootFrame.CanGoBack) { rootFrame.GoBack(); } } // Navega de vuelta a la vista anterior, pasándole parámetros complejos a su vista-modelo /// <summary> /// Navigates the back. /// </summary> /// <param name="navigationContext">The navigation context.</param> public void NavigateBack(object navigationContext) { // Parámetros para el vista-modelo this.navigationContext = navigationContext; // Navega a la página anterior y entérate de cuándo hemos llegado PhoneApplicationFrame rootFrame = Application.Current.RootVisual as PhoneApplicationFrame; if (rootFrame.CanGoBack) { rootFrame.Navigated += new NavigatedEventHandler(Page_Navigated); rootFrame.GoBack(); } } // Ya hemos llegado a la página a cuyo vista-modelo queremos pasarle los parámetros /// <summary> /// Handles the Navigated event of the Page control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param> private void Page_Navigated(object sender, NavigationEventArgs e) { PhoneApplicationFrame rootFrame = Application.Current.RootVisual as PhoneApplicationFrame; rootFrame.Navigated -= Page_Navigated; // Pásale los parámetros a su vista-modelo ((e.Content as PhoneApplicationPage).DataContext as INavigable).NavigationContext = this.navigationContext; } // Limpia el historial de navegación entre páginas /// <summary> /// Clears the navigation history. /// </summary> public void ClearNavigationHistory() { PhoneApplicationFrame rootFrame = Application.Current.RootVisual as PhoneApplicationFrame; while (rootFrame.RemoveBackEntry() != null) ; } }

5. Para hacer la navegación solo falta implementar la interfaz e llamar la navigationTo<>:

Para poder utilizar nuestro NavigationService, debemos de implementarlo por inyección de dependencias en nuestra ViewModel y llamar a NavigateTo<>.

public ICommand AboutCommand { get; private set; } private void AboutCommandDelegate() { navigationService.NavigateTo<AboutViewModel>(); }

6. Para recibir los datos:

Para recibir los datos implementamos la interfaz INavigable y en su set declaramos toda la lógica necesaria para el manejo correcto de dichos datos.

public class MainViewModel : ViewModelBase, INavigable { private readonly INavigationService navigationService; public MainViewModel(INavigationService navigationService) { this.navigationService = navigationService; } public object NavigationContext { set { // Trabajar con el Objeto pasado para esta Pagina. } } }

Hasta aquí llega otro tutorial. Si os ha gustado no os lo quedéis para vosotros, compartid ;)

Happy Coding!