I already have a solution for allowing the view model to jump back onto the UI thread using the UIContext. However, I currently don’t have a mechanism that will allow one view model initiate navigation to a new page/view. What I want is the ability for one view model to request navigation by specifying the destination view model. Of course, this needs to work cross platform. Let’s take a look at the basics of how this could work – there are essentially two strategies that most mvvm style navigation frameworks use: The first is by convention where the lookup for the destination page/view is based on the name of the target view model; the second is by defining a mapping between view models and the corresponding page/view. In this case I’m going to go with the latter – In the Core library I define a couple of interfaces and an abstract implementation:
public interface INavigateService
{
void Navigate<TViewModel>() where TViewModel : IDataViewModel;
}public interface INativeNavigateService<TView> : INavigateService
where TView : class,new()
{
void Register<TViewModel, TViewType>() where TViewType : TView;
}public abstract class CoreNavigateService<TView> : INativeNavigateService<TView> where TView : class, new()
{
private readonly IDictionary<Type, Type> viewDictionary = new Dictionary<Type, Type>();protected Type ViewType<TViewModel>()
{
Type viewType = null;
viewDictionary.TryGetValue(typeof(TViewModel), out viewType);
return viewType;
}public void Register<TViewModel, TViewType>() where TViewType : TView
{
viewDictionary[typeof(TViewModel)] = typeof(TView);
}public void Navigate<TViewModel>() where TViewModel : IDataViewModel
{
var navType = ViewType<TViewModel>();
NavigateToView(navType);
}protected abstract void NavigateToView(Type viewType);
}
Next, in the client projects, I define a class that inherits from CoreNavigateService and implements the NavigateToView method. Here is the Windows Platform implementation:
public class WindowsPlatformNavigationService : CoreNavigateService<Page>
{
protected override void NavigateToView(Type viewType)
{
(Window.Current.Content as Frame).Navigate(viewType);
}
}
The ApplicationStartup method now looks like:
public void ApplicationStartup()
{
CoreApplication.Startup(builder =>
{builder.RegisterType<SignalRFactory>().As<ISignalR>();
#if NETFX_CORE
builder.RegisterType<UniversalUIContext>().As<IUIContext>();builder.RegisterType<WindowsPlatformNavigationService>().SingleInstance().As<INavigateService>();
#endif
});var navService = ServiceLocator.Current.GetInstance<INavigateService>() as WindowsPlatformNavigationService;
#if NETFX_CORE
navService.Register<MainViewModel,MainPage>();
navService.Register<SecondViewModel,SecondPage>();
#endif
}
Both the IDataViewModel, BaseViewModel and ViewModelLocator need to be extended to include an INavigateService property called NavigateService. Now from within the view model, navigation can be invoked by calling NavigateService.Navigate<SecondViewModel>()