internal async Task <bool> Navigate(Type viewModelType, object[] arguments, XamlNav.NavigationMode navigationMode, NavigationType navigationType) { if (!await this.CanChangePage(viewModelType, navigationMode, navigationType)) { return(false); } FrameworkElement view = null; IViewModel viewModel = null; // Create a view if (navigationMode == XamlNav.NavigationMode.Back || navigationMode == XamlNav.NavigationMode.Forward || navigationMode == XamlNav.NavigationMode.New) { view = GetView(viewModelType); } // Create a view model if (navigationMode == XamlNav.NavigationMode.Back || navigationMode == XamlNav.NavigationMode.Forward || navigationMode == XamlNav.NavigationMode.Refresh) { viewModel = Factory.Create(viewModelType, arguments).As <IViewModel>(); // Use Factory create here so that the factory extensions are invoked } // Bind the IsLoading if implemented if (view != null) { view.SetBinding(Control.IsEnabledProperty, new Binding { Path = new PropertyPath(nameof(IViewModel.IsLoading)), Converter = new BooleanInvertConverter() }); } if (navigationMode == XamlNav.NavigationMode.Back || navigationMode == XamlNav.NavigationMode.Forward) { // Setup the page transition animations if (view.Transitions != null && view.Transitions.Count > 0) { this.ContentTransitions = view.Transitions; } else { this.ContentTransitions = this.DefaultChildrenTransitions; } // we need to keep our old datacontext to dispose them properly later on var oldDataContext = this.ContentDataContext; var oldView = this.Content.As <FrameworkElement>(); // Assign our new content this.Content = view; await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => view.DataContext = viewModel); // Invoke the Navigation stuff in the current datacontext await AsyncHelper.NullGuard(viewModel.As <INavigable>()?.OnNavigatedTo(new NavigationInfo(navigationMode, navigationType, oldDataContext?.GetType()))); // Remove the reference of the old vm from the old view oldView.IsNotNull(x => x.DataContext = null); // Now invoke the navigated from on our old data context await AsyncHelper.NullGuard(oldDataContext?.As <INavigable>()?.OnNavigatedFrom(new NavigationInfo(navigationMode, navigationType, viewModelType))); // dispose the old viewmodel oldDataContext?.TryDispose(); } else if (navigationMode == XamlNav.NavigationMode.New) { // NavigationMode.New means recreate the view but preserve the viewmodel // we need to keep our current datacontext for later reassigning var currentDataContext = this.ContentDataContext; var oldView = this.Content.As <FrameworkElement>(); // cancel this if the oldview and the new view are the same if (oldView.GetType() == view.GetType()) { return(false); } // Assign our content this.Content = view; await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => view.DataContext = currentDataContext); // Invoke the Navigation stuff in the current datacontext await AsyncHelper.NullGuard(currentDataContext.As <INavigable>()?.OnNavigatedTo(new NavigationInfo(navigationMode, navigationType, currentDataContext.GetType()))); // Remove the reference of the current viewmodel from the old view oldView.IsNotNull(x => x.DataContext = null); } else if (navigationMode == XamlNav.NavigationMode.Refresh) { // we need to keep our old datacontext to dispose them properly later on var oldDataContext = this.ContentDataContext; // NavigationMode.Refresh means recreate the view model but preserve the view viewModel = Factory.Create(viewModelType, arguments).As <IViewModel>(); await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => view.DataContext = viewModel); // Invoke the Navigation stuff in the current datacontext await AsyncHelper.NullGuard(viewModel.As <INavigable>()?.OnNavigatedTo(new NavigationInfo(navigationMode, navigationType, viewModelType))); // dispose the old viewmodel oldDataContext?.TryDispose(); } // Refresh the stacks if (navigationMode == XamlNav.NavigationMode.Forward) { // we have to check if the current viewmodel is the same as the one the top of the forwardstack // if that is the case we remove it from the stack // if that is not the case, then we clear the stack if (this.ForwardStack.Count > 0) { var stackEntry = this.ForwardStack[0]; // Remove the stack if equal if (viewModelType == stackEntry.ViewModelType && ((stackEntry.Parameters != null && arguments != null && stackEntry.Parameters.SequenceEqual(arguments)) || (stackEntry.Parameters == null && arguments == null))) { this.ForwardStack.RemoveAt(0); } else { this.ForwardStack.Clear(); } } } if (navigationMode == XamlNav.NavigationMode.Back || navigationMode == XamlNav.NavigationMode.Forward) { this.BackStack.Add(new PageStackEntry(viewModelType, arguments)); } // remove entries from stack if (this.MaxStackSize > 1) { if (this.BackStack.Count > this.MaxStackSize + 1) { this.BackStack.RemoveAt(0); } if (this.ForwardStack.Count > this.MaxStackSize) { this.ForwardStack.RemoveAt(this.ForwardStack.Count - 1); } } this.CanGoBack = this.BackStack.Count > 1; this.CanGoForward = this.ForwardStack.Count > 0; this.Navigated?.Invoke(this, EventArgs.Empty); return(true); }
private async void OpenInfoAction(IViewModel arg) => await this.Navigator.NavigateAsync <ItemInfoViewModel>(arg.As <TypeNameItemViewModel>().ItemId);