public void DestroyContentPage() { var recorder = new PageNavigationEventRecorder(); var page = new ContentPageMock(recorder); var viewModel = (ViewModelBase)page.BindingContext; PageUtilities.DestroyPage(page); Assert.Equal(2, recorder.Records.Count); Assert.Equal(page, recorder.Records[0].Sender); Assert.Null(page.BindingContext); Assert.Equal(0, page.Behaviors.Count); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[0].Event); Assert.Equal(viewModel, recorder.Records[1].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[1].Event); }
/// <summary> /// Navigates to the most recent entry in the back navigation history by popping the calling Page off the navigation stack. /// </summary> /// <param name="parameters">The navigation parameters</param> /// <param name="useModalNavigation">If <c>true</c> uses PopModalAsync, if <c>false</c> uses PopAsync</param> /// <param name="animated">If <c>true</c> the transition is animated, if <c>false</c> there is no animation on transition.</param> /// <returns>If <c>true</c> a go back operation was successful. If <c>false</c> the go back operation failed.</returns> public virtual async Task <bool> GoBackAsync(NavigationParameters parameters = null, bool?useModalNavigation = null, bool animated = true) { try { NavigationSource = PageNavigationSource.NavigationService; var page = GetCurrentPage(); var segmentParameters = UriParsingHelper.GetSegmentParameters(null, parameters); segmentParameters.Add(KnownNavigationParameters.NavigationMode, NavigationMode.Back); var canNavigate = await PageUtilities.CanNavigateAsync(page, segmentParameters); if (!canNavigate) { return(false); } bool useModalForDoPop = UseModalNavigation(page, useModalNavigation); Page previousPage = PageUtilities.GetOnNavigatedToTarget(page, _applicationProvider.MainPage, useModalForDoPop); PageUtilities.OnNavigatingTo(previousPage, segmentParameters); var poppedPage = await DoPop(page.Navigation, useModalForDoPop, animated); if (poppedPage != null) { PageUtilities.OnNavigatedFrom(page, segmentParameters); PageUtilities.OnNavigatedTo(previousPage, segmentParameters); PageUtilities.DestroyPage(poppedPage); return(true); } } catch (Exception e) { _logger.Log(e.ToString(), Category.Exception, Priority.High); return(false); } finally { NavigationSource = PageNavigationSource.Device; } return(false); }
public void DestroyNavigationPage() { var recorder = new PageNavigationEventRecorder(); var navigationPage = new NavigationPageMock(recorder); var navigationPageViewModel = navigationPage.BindingContext; var contentPage1 = navigationPage.CurrentPage; var contentPage1ViewModel = contentPage1.BindingContext; var contentPage2 = new ContentPageMock(recorder); var contentPage2ViewModel = contentPage2.BindingContext; contentPage1.Navigation.PushAsync(contentPage2); PageUtilities.DestroyPage(navigationPage); Assert.Equal(6, recorder.Records.Count); // contentPage2 Assert.Equal(contentPage2, recorder.Records[0].Sender); Assert.Null(contentPage2.BindingContext); Assert.Equal(0, contentPage2.Behaviors.Count); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[0].Event); Assert.Equal(contentPage2ViewModel, recorder.Records[1].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[1].Event); // contentPage1 Assert.Equal(contentPage1, recorder.Records[2].Sender); Assert.Null(contentPage1.BindingContext); Assert.Equal(0, contentPage1.Behaviors.Count); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[2].Event); Assert.Equal(contentPage1ViewModel, recorder.Records[3].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[3].Event); // navigationPage Assert.Equal(navigationPage, recorder.Records[4].Sender); Assert.Null(navigationPage.BindingContext); Assert.Equal(0, navigationPage.Behaviors.Count); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[4].Event); Assert.Equal(navigationPageViewModel, recorder.Records[5].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[5].Event); }
public override async Task <bool> GoBackAsync(INavigationParameters parameters = null, bool?useModalNavigation = default(bool?), bool animated = true) { try { NavigationSource = PageNavigationSource.NavigationService; switch (PopupUtilities.TopPage(_popupNavigation, _applicationProvider)) { case PopupPage popupPage: var segmentParameters = UriParsingHelper.GetSegmentParameters(null, parameters); segmentParameters.Add(KnownNavigationParameters.NavigationMode, NavigationMode.Back); var previousPage = PopupUtilities.GetOnNavigatedToTarget(_popupNavigation, _applicationProvider); PageUtilities.OnNavigatingTo(previousPage, segmentParameters); await DoPop(popupPage.Navigation, false, animated); if (popupPage != null) { PageUtilities.InvokeViewAndViewModelAction <IActiveAware>(popupPage, a => a.IsActive = false); PageUtilities.OnNavigatedFrom(popupPage, segmentParameters); PageUtilities.OnNavigatedTo(previousPage, segmentParameters); PageUtilities.InvokeViewAndViewModelAction <IActiveAware>(previousPage, a => a.IsActive = true); PageUtilities.DestroyPage(popupPage); return(true); } break; default: return(await base.GoBackAsync(parameters, useModalNavigation, animated)); } } catch (Exception e) { _logger.Log(e.ToString(), Category.Exception, Priority.High); return(false); } finally { NavigationSource = PageNavigationSource.Device; } return(false); }
public void DestroyCarouselPage() { var recorder = new PageNavigationEventRecorder(); var carouselPage = new CarouselPageMock(recorder); var carouselPageViewModel = carouselPage.BindingContext; var childPage2 = carouselPage.Children[1]; var childPage2ViewModel = childPage2.BindingContext; PageUtilities.DestroyPage(carouselPage); Assert.Equal(6, recorder.Records.Count); // childPage3 : This page is ContentPage. Assert.Equal(carouselPageViewModel, recorder.Records[0].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[0].Event); // childPage2 Assert.Equal(childPage2, recorder.Records[1].Sender); Assert.Null(childPage2.BindingContext); Assert.Equal(0, childPage2.Behaviors.Count); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[1].Event); Assert.Equal(childPage2ViewModel, recorder.Records[2].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[2].Event); // childPage1 : This page is ContentPage. Assert.Equal(carouselPageViewModel, recorder.Records[3].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[3].Event); // tabbedPage Assert.Equal(carouselPage, recorder.Records[4].Sender); Assert.Null(carouselPage.BindingContext); Assert.Equal(0, carouselPage.Behaviors.Count); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[4].Event); Assert.Equal(carouselPageViewModel, recorder.Records[5].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[5].Event); }
protected virtual async Task ProcessNavigationForMasterDetailPage(MasterDetailPage currentPage, string nextSegment, Queue <string> segments, INavigationParameters parameters, bool?useModalNavigation, bool animated) { bool isPresented = GetMasterDetailPageIsPresented(currentPage); var detail = currentPage.Detail; if (detail == null) { var newDetail = CreatePageFromSegment(nextSegment); await ProcessNavigation(newDetail, segments, parameters, useModalNavigation, animated); await DoNavigateAction(null, nextSegment, newDetail, parameters, onNavigationActionCompleted : () => { currentPage.IsPresented = isPresented; currentPage.Detail = newDetail; }); return; } if (useModalNavigation.HasValue && useModalNavigation.Value) { var nextPage = CreatePageFromSegment(nextSegment); await ProcessNavigation(nextPage, segments, parameters, useModalNavigation, animated); await DoNavigateAction(currentPage, nextSegment, nextPage, parameters, async() => { currentPage.IsPresented = isPresented; await DoPush(currentPage, nextPage, true, animated); }); return; } var nextSegmentType = PageNavigationRegistry.GetPageType(UriParsingHelper.GetSegmentName(nextSegment)); //we must recreate the NavigationPage everytime or the transitions on iOS will not work properly, unless we meet the two scenarios below bool detailIsNavPage = false; bool reuseNavPage = false; if (detail is NavigationPage navPage) { detailIsNavPage = true; //first we check to see if we are being forced to reuse the NavPage by checking the interface reuseNavPage = !GetClearNavigationPageNavigationStack(navPage); if (!reuseNavPage) { //if we weren't forced to reuse the NavPage, then let's check the NavPage.CurrentPage against the next segment type as we don't want to recreate the entire nav stack //just in case the user is trying to navigate to the same page which may be nested in a NavPage var nextPageType = PageNavigationRegistry.GetPageType(UriParsingHelper.GetSegmentName(segments.Peek())); var currentPageType = navPage.CurrentPage.GetType(); if (nextPageType == currentPageType) { reuseNavPage = true; } } } if ((detailIsNavPage && reuseNavPage) || (!detailIsNavPage && detail.GetType() == nextSegmentType)) { await ProcessNavigation(detail, segments, parameters, useModalNavigation, animated); await DoNavigateAction(null, nextSegment, detail, parameters, onNavigationActionCompleted : () => { currentPage.IsPresented = isPresented; }); return; } else { var newDetail = CreatePageFromSegment(nextSegment); await ProcessNavigation(newDetail, segments, parameters, newDetail is NavigationPage?false : true, animated); await DoNavigateAction(detail, nextSegment, newDetail, parameters, onNavigationActionCompleted : () => { currentPage.IsPresented = isPresented; currentPage.Detail = newDetail; PageUtilities.DestroyPage(detail); }); return; } }
protected virtual async Task ProcessNavigationForNavigationPage(NavigationPage currentPage, string nextSegment, Queue <string> segments, INavigationParameters parameters, bool?useModalNavigation, bool animated) { if (currentPage.Navigation.NavigationStack.Count == 0) { await UseReverseNavigation(currentPage, nextSegment, segments, parameters, false, animated); return; } var clearNavigationStack = GetClearNavigationPageNavigationStack(currentPage); var isEmptyOfNavigationStack = currentPage.Navigation.NavigationStack.Count == 0; List <Page> destroyPages; if (clearNavigationStack && !isEmptyOfNavigationStack) { destroyPages = currentPage.Navigation.NavigationStack.ToList(); destroyPages.Reverse(); await currentPage.Navigation.PopToRootAsync(false); } else { destroyPages = new List <Page>(); } var topPage = currentPage.Navigation.NavigationStack.LastOrDefault(); var nextPageType = PageNavigationRegistry.GetPageType(UriParsingHelper.GetSegmentName(nextSegment)); if (topPage?.GetType() == nextPageType) { if (clearNavigationStack) { destroyPages.Remove(destroyPages.Last()); } if (segments.Count > 0) { await UseReverseNavigation(topPage, segments.Dequeue(), segments, parameters, false, animated); } await DoNavigateAction(topPage, nextSegment, topPage, parameters, onNavigationActionCompleted : () => { if (nextSegment.Contains(KnownNavigationParameters.SelectedTab)) { var segmentParams = UriParsingHelper.GetSegmentParameters(nextSegment); SelectPageTab(topPage, segmentParams); } }); } else { await UseReverseNavigation(currentPage, nextSegment, segments, parameters, false, animated); if (clearNavigationStack && !isEmptyOfNavigationStack) { currentPage.Navigation.RemovePage(topPage); } } foreach (var destroyPage in destroyPages) { PageUtilities.DestroyPage(destroyPage); } }
public void DestroyTabbedPage() { var recorder = new PageNavigationEventRecorder(); var tabbedPage = new TabbedPageMock(recorder); var tabbedPageViewModel = tabbedPage.BindingContext; var tab1 = tabbedPage.Children[0]; var tab1ViewModel = tab1.BindingContext; var tab2 = tabbedPage.Children[1]; var tab2ViewModel = tab2.BindingContext; var tab3 = tabbedPage.Children[2]; var tab3ViewModel = tab3.BindingContext; var tab4 = tabbedPage.Children[3]; var tab4Child = ((NavigationPage)tab4).CurrentPage; var tab4ViewModel = tab4.BindingContext; var tab4ChildViewModel = tab4Child.BindingContext; var tab5 = tabbedPage.Children[4]; var tab5Child = ((NavigationPage)tab5).CurrentPage; var tab5ViewModel = tab5.BindingContext; var tab5ChildViewModel = tab5Child.BindingContext; PageUtilities.DestroyPage(tabbedPage); Assert.Equal(13, recorder.Records.Count); //tab 5 Assert.Equal(tab5ViewModel, recorder.Records[0].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[0].Event); Assert.Equal(tab5, recorder.Records[1].Sender); Assert.Equal(0, tab5.Behaviors.Count); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[1].Event); Assert.Equal(tab5ChildViewModel, recorder.Records[2].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[2].Event); //tab 4 Assert.Equal(tab4Child, recorder.Records[3].Sender); Assert.Equal(0, tab4Child.Behaviors.Count); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[3].Event); Assert.Equal(tab4ChildViewModel, recorder.Records[4].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[4].Event); Assert.Equal(tab4, recorder.Records[5].Sender); Assert.Equal(0, tab4.Behaviors.Count); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[5].Event); Assert.Equal(tab4ViewModel, recorder.Records[6].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[6].Event); //tab 3 Assert.Equal(tab3, recorder.Records[7].Sender); Assert.Null(tab3.BindingContext); Assert.Equal(0, tab3.Behaviors.Count); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[7].Event); Assert.Equal(tab3ViewModel, recorder.Records[8].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[8].Event); //tab 2 : PageMock has no binding context so it has no entries. //tab 1 Assert.Equal(tab1, recorder.Records[9].Sender); Assert.Null(tab1.BindingContext); Assert.Equal(0, tab1.Behaviors.Count); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[9].Event); Assert.Equal(tab1ViewModel, recorder.Records[10].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[10].Event); //TabbedPage Assert.Equal(tabbedPage, recorder.Records[11].Sender); Assert.Null(tabbedPage.BindingContext); Assert.Equal(0, tabbedPage.Behaviors.Count); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[11].Event); Assert.Equal(tabbedPageViewModel, recorder.Records[12].Sender); Assert.Equal(PageNavigationEvent.Destroy, recorder.Records[12].Event); }
public static async Task <INavigationResult> GoBackToTargetInternal <T>(INavigationParameters parameters) { _logger?.Log(); var result = new NavigationResult(); try { if (parameters == null) { parameters = new NavigationParameters(); } ((INavigationParametersInternal)parameters).Add("__NavigationMode", NavigationMode.Back); // __NavigationMode is hardcode of Prism.Navigation.KnownInternalParameters.NavigationMode var currentPage = PageUtilities.GetCurrentPage(Application.Current.MainPage); NavigationPage navigationPage = null; var tmp = currentPage; while (tmp.Parent != null) { if (tmp.Parent is NavigationPage) { navigationPage = tmp.Parent as NavigationPage; break; } else { tmp = tmp.Parent as Page; } } if (navigationPage == null) { result.Exception = new NavigationException("Require NavigationPage", currentPage); return(result); } var canNavigate = await PageUtilities.CanNavigateAsync(currentPage, parameters); if (!canNavigate) { result.Exception = new NavigationException(NavigationException.IConfirmNavigationReturnedFalse, currentPage); return(result); } // Cache the stack to avoid mutation. var stack = currentPage.Navigation.NavigationStack.ToList(); Page root = navigationPage.RootPage; // Initial root value. var pagesToDestroy = new List <Page>(); // For stack, A > B > C > D. We want to navigate from D to B. // A > B > D. // The remove order is D > C. for (int i = stack.Count - 1; i >= 1; i--) // i = 0 is root page. we don't remove it. { var page = stack[i]; if (page.BindingContext.GetType() == typeof(T)) // Assume target key is ViewModel's name. { root = page; // Root is B. break; } pagesToDestroy.Add(page); } // Temporary remove prism navigation aware var systemGoBackBehavior = navigationPage.Behaviors.FirstOrDefault(p => p is NavigationPageSystemGoBackBehavior); if (systemGoBackBehavior != null) { navigationPage.Behaviors.Remove(systemGoBackBehavior); } for (int i = 1; i < pagesToDestroy.Count; i++) // Skip page D, remove page C, { currentPage.Navigation.RemovePage(pagesToDestroy[i]); } await currentPage.Navigation.PopAsync(); // Navigate from D to B. foreach (var destroyPage in pagesToDestroy) // D, C OnNavigatedFrom and Destroy { PageUtilities.OnNavigatedFrom(destroyPage, parameters); PageUtilities.DestroyPage(destroyPage); } PageUtilities.OnNavigatedTo(root, parameters); // B OnNavigatedTo // Re-add prism navigation aware if (systemGoBackBehavior != null) { navigationPage.Behaviors.Add(systemGoBackBehavior); } result.Success = true; return(result); } catch (Exception ex) { result.Exception = ex; return(result); } }
protected virtual async Task ProcessNavigationForNavigationPage(NavigationPage currentPage, string nextSegment, Queue <string> segments, NavigationParameters parameters, bool?useModalNavigation, bool animated) { if (currentPage.Navigation.NavigationStack.Count == 0) { await UseReverseNavigation(currentPage, nextSegment, segments, parameters, false, animated); return; } var clearNavigationStack = GetClearNavigationPageNavigationStack(currentPage); var isEmptyOfNavigationStack = currentPage.Navigation.NavigationStack.Count == 0; List <Page> destroyPages; if (clearNavigationStack && !isEmptyOfNavigationStack) { destroyPages = currentPage.Navigation.NavigationStack.ToList(); destroyPages.Reverse(); await currentPage.Navigation.PopToRootAsync(false); } else { destroyPages = new List <Page>(); } var topPage = currentPage.Navigation.NavigationStack.LastOrDefault(); var nextPageType = PageNavigationRegistry.GetPageType(UriParsingHelper.GetSegmentName(nextSegment)); if (topPage?.GetType() == nextPageType) { if (clearNavigationStack) { destroyPages.Remove(destroyPages.Last()); } await ProcessNavigation(topPage, segments, parameters, false, animated); await DoNavigateAction(topPage, nextSegment, topPage, parameters); } else { // Replace RootPage of NavigationStack var nextPage = CreatePageFromSegment(nextSegment); await ProcessNavigation(nextPage, segments, parameters, false, animated); await DoNavigateAction(topPage ?? currentPage, nextSegment, nextPage, parameters, async() => { var push = DoPush(currentPage, nextPage, false, animated); if (clearNavigationStack && !isEmptyOfNavigationStack) { currentPage.Navigation.RemovePage(topPage); } await push; }); } foreach (var destroyPage in destroyPages) { PageUtilities.DestroyPage(destroyPage); } }