[MVVM] Navegación entre Páginas en Windows Phone 8.1 Silverlight
![[MVVM] Navegación entre Páginas en Windows Phone 8.1 Silverlight](/content/images/size/w2000/2014/10/MVVMNavigationServiceTutorial.png)

¡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!