private async Task <bool> NavigationOrchestratorAsync(Type page, object parameter, NavigationMode mode, Func <bool> navigate) { try { await _navigationOrchestratorAsyncSemaphore.WaitAsync(); this.Log($"Page: {page}, Parameter: {parameter}, NavigationMode: {mode}"); if (page == null) { throw new ArgumentNullException(nameof(page)); } if (navigate == null) { throw new ArgumentNullException(nameof(navigate)); } // this cannot be used for duplicate navigation, except for refresh if (!Equals(mode, NavigationMode.Refresh)) { if (Equals(page, CurrentPageType)) { if (Equals(parameter, CurrentPageParam)) { return(false); } } } // fetch current (which will become old) var fromPage = FrameEx.Content as Page; var fromParameter = CurrentPageParam; var fromViewModel = fromPage?.DataContext; var fromPageName = fromPage?.GetType().ToString(); var fromPageState = await FrameEx2.GetPageStateAsync(fromPage?.GetType()); var from = new NavigationInfo(fromPage?.GetType(), fromParameter, fromPageState); var toPageName = page?.ToString(); var toPageState = await FrameEx2.GetPageStateAsync(toPageName); var to = new NavigationInfo(page, parameter, toPageState); // call fromViewModel.OnNavigatingFromAsync() var NavigatingFromAsyncResult = await ViewModelActionStrategy.NavigatingFromAsync(fromViewModel, mode, false, from, to, this); if (NavigatingFromAsyncResult == ContinueResult.Stop) { return(false); } // raise Navigating event Two.RaiseNavigatingCancels(parameter, false, mode, to, out var RaiseNavigatingCancelsResult); if (RaiseNavigatingCancelsResult == ContinueResult.Stop) { return(false); } // try to resolve the view-model before navigation var newViewModel = await ViewModelResolutionStrategy.ResolveViewModelAsync(page); if (newViewModel != null) { if (newViewModel is ITemplate10ViewModel t) { t.NavigationService = this; } await ViewModelActionStrategy.NavigatingToAsync(newViewModel, mode, false, from, to, this); } // navigate var newPage = default(Page); if (navigate.Invoke()) { if ((newPage = FrameEx.Content as Page) == null) { return(false); } CurrentPageParam = parameter; CurrentPageType = page; } else { return(false); } // fetch current (which is now new) if (newViewModel != null) { newPage.DataContext = newViewModel; } else if ((newViewModel = newPage?.DataContext) != null) { await ViewModelActionStrategy.NavigatingToAsync(newViewModel, mode, false, from, to, this); } // raise Navigated event Two.RaiseNavigated(new NavigatedEventArgs() { Parameter = parameter, NavigationMode = mode, PageType = newPage?.GetType(), }); // call fromViewModel.OnNavigatedFrom() await ViewModelActionStrategy.NavigatedFromAsync(fromViewModel, mode, false, from, to, this); // call toTemplate10ViewModel.Properties if (newViewModel is ITemplate10ViewModel vm) { vm.NavigationService = this; } // call newViewModel.OnNavigatedToAsync() await ViewModelActionStrategy.NavigatedToAsync(newViewModel, mode, false, from, to, this); // finally, all-good return(true); } catch (Exception ex) { this.Log(ex.Message, Severities.Error); Debugger.Break(); throw; } finally { _navigationOrchestratorAsyncSemaphore.Release(); } }
void INavigationService2.RaiseNavigatingCancels(object parameter, bool suspending, NavigationMode mode, NavigationInfo toInfo, out ContinueResult cancel) { var navigatingDeferral = new Common.DeferralExManager(); var navigatingEventArgs = new NavigatingEventArgs(navigatingDeferral) { Parameter = parameter, Suspending = suspending, NavigationMode = mode, TargetPageType = toInfo.PageType, TargetPageParameter = toInfo.Parameter, }; Navigating?.Invoke(this, navigatingEventArgs); cancel = navigatingEventArgs.Cancel ? ContinueResult.Stop : ContinueResult.Continue; }