private static async Task OnNavigatingToAsync(Page toPage, INavigationParameters parameters)
        {
            PageUtilities.OnNavigatingTo(toPage, parameters);
            await PageUtilitiesExtended.OnNavigatingToAsync(toPage, parameters);

            if (toPage is TabbedPage tabbedPage)
            {
                if (tabbedPage.CurrentPage is NavigationPage navigationPage)
                {
                    PageUtilities.OnNavigatingTo(navigationPage.CurrentPage, parameters);
                    await PageUtilitiesExtended.OnNavigatingToAsync(navigationPage.CurrentPage, parameters);
                }
                else
                {
                    PageUtilities.OnNavigatingTo(tabbedPage.CurrentPage, parameters);
                    await PageUtilitiesExtended.OnNavigatingToAsync(tabbedPage.CurrentPage, parameters);
                }
            }
            else if (toPage is CarouselPage carouselPage)
            {
                foreach (var child in carouselPage.Children)
                {
                    PageUtilities.OnNavigatingTo(child, parameters);
                    await PageUtilitiesExtended.OnNavigatingToAsync(child, parameters);
                }
            }
        }
        void ConfigureTabbedPage(TabbedPage tabbedPage, string segment)
        {
            foreach (var child in tabbedPage.Children)
            {
                PageUtilitiesExtended.SetAutowireViewModelOnPage(child);
                _pageBehaviorFactory.ApplyPageBehaviors(child);
                if (child is NavigationPage navPage)
                {
                    PageUtilitiesExtended.SetAutowireViewModelOnPage(navPage.CurrentPage);
                    _pageBehaviorFactory.ApplyPageBehaviors(navPage.CurrentPage);
                }
            }

            var parameters = UriParsingHelper.GetSegmentParameters(segment);

            var tabsToCreate = parameters.GetValues <string>(KnownNavigationParameters.CreateTab);

            if (tabsToCreate.Count() > 0)
            {
                foreach (var tabToCreate in tabsToCreate)
                {
                    //created tab can be a single view or a view nested in a NavigationPage with the syntax "NavigationPage|ViewToCreate"
                    var tabSegements = tabToCreate.Split('|');
                    if (tabSegements.Length > 1)
                    {
                        var navigationPage = CreatePageFromSegment(tabSegements[0]) as NavigationPage;
                        if (navigationPage != null)
                        {
                            var navigationPageChild = CreatePageFromSegment(tabSegements[1]);

                            navigationPage.PushAsync(navigationPageChild);

                            //when creating a NavigationPage w/ DI, a blank Page object is injected into the ctor. Let's remove it
                            if (navigationPage.Navigation.NavigationStack.Count > 1)
                            {
                                navigationPage.Navigation.RemovePage(navigationPage.Navigation.NavigationStack[0]);
                            }

                            //set the title because Xamarin doesn't do this for us.
                            navigationPage.Title = navigationPageChild.Title;
                            navigationPage.Icon  = navigationPageChild.Icon;

                            tabbedPage.Children.Add(navigationPage);
                        }
                    }
                    else
                    {
                        var tab = CreatePageFromSegment(tabToCreate);
                        tabbedPage.Children.Add(tab);
                    }
                }
            }

            TabbedPageSelectTab(tabbedPage, parameters);
        }
        void ConfigureCarouselPage(CarouselPage carouselPage, string segment)
        {
            foreach (var child in carouselPage.Children)
            {
                PageUtilitiesExtended.SetAutowireViewModelOnPage(child);
            }

            var parameters = UriParsingHelper.GetSegmentParameters(segment);

            CarouselPageSelectTab(carouselPage, parameters);
        }
        /// <summary>
        /// When navigating inside a NavigationPage: Pops all but the root Page off the navigation stack
        /// </summary>
        /// <param name="navigationService">The INavigatinService instance</param>
        /// <param name="parameters">The navigation parameters</param>
        /// <remarks>Only works when called from a View within a NavigationPage</remarks>
        protected virtual async Task <INavigationResult> GoBackToRootInternal(INavigationParameters parameters)
        {
            var result = new NavigationResult();

            try
            {
                if (parameters == null)
                {
                    parameters = new NavigationParameters();
                }

                parameters.GetNavigationParametersInternal().Add(KnownInternalParameters.NavigationMode, NavigationMode.Back);

                var page        = GetCurrentPage();
                var canNavigate = await PageUtilities.CanNavigateAsync(page, parameters);

                if (!canNavigate)
                {
                    result.Exception = new Exception($"IConfirmNavigation for {page} returned false");
                    return(result);
                }

                List <Page> pagesToDestroy = page.Navigation.NavigationStack.ToList(); // get all pages to destroy
                pagesToDestroy.Reverse();                                              // destroy them in reverse order
                var root = pagesToDestroy.Last();
                pagesToDestroy.Remove(root);                                           //don't destroy the root page

                PageUtilities.OnNavigatingTo(root, parameters);
                await PageUtilitiesExtended.OnNavigatingToAsync(root, parameters);

                await page.Navigation.PopToRootAsync();

                foreach (var destroyPage in pagesToDestroy)
                {
                    PageUtilities.OnNavigatedFrom(destroyPage, parameters);
                    PageUtilities.DestroyPage(destroyPage);
                }

                PageUtilities.OnNavigatedTo(root, parameters);

                result.Success = true;
                return(result);
            }
            catch (InvalidOperationException ex)
            {
                result.Exception = new Exception("GoBackToRootAsync can only be called when the calling Page is within a NavigationPage.", ex);
                return(result);
            }
            catch (Exception ex)
            {
                result.Exception = ex;
                return(result);
            }
        }
        /// <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>
        protected virtual async Task <INavigationResult> GoBackInternal(INavigationParameters parameters, bool?useModalNavigation, bool animated)
        {
            var result = new NavigationResult();

            try
            {
                NavigationSource = PageNavigationSource.NavigationService;

                var page = GetCurrentPage();
                var segmentParameters = UriParsingHelper.GetSegmentParameters(null, parameters);
                segmentParameters.GetNavigationParametersInternal().Add(KnownInternalParameters.NavigationMode, NavigationMode.Back);

                var canNavigate = await PageUtilities.CanNavigateAsync(page, segmentParameters);

                if (!canNavigate)
                {
                    result.Exception = new Exception($"IConfirmNavigation for {page} returned false");
                    return(result);
                }

                bool useModalForDoPop = UseModalNavigation(page, useModalNavigation);
                Page previousPage     = PageUtilities.GetOnNavigatedToTarget(page, _applicationProvider.MainPage, useModalForDoPop);

                PageUtilities.OnNavigatingTo(previousPage, segmentParameters);
                await PageUtilitiesExtended.OnNavigatingToAsync(previousPage, segmentParameters);

                var poppedPage = await DoPop(page.Navigation, useModalForDoPop, animated);

                if (poppedPage != null)
                {
                    PageUtilities.OnNavigatedFrom(page, segmentParameters);
                    PageUtilities.OnNavigatedTo(previousPage, segmentParameters);
                    PageUtilities.DestroyPage(poppedPage);

                    result.Success = true;
                    return(result);
                }
            }
            catch (Exception ex)
            {
                _logger.Log(ex.ToString(), Category.Exception, Priority.High);
                result.Exception = ex;
                return(result);
            }
            finally
            {
                NavigationSource = PageNavigationSource.Device;
            }

            result.Exception = new Exception("Unknown error occured.");
            return(result);
        }
        protected virtual Task ProcessNavigationForRemovePageSegments(Page currentPage, string nextSegment, Queue <string> segments, INavigationParameters parameters, bool?useModalNavigation, bool animated)
        {
            if (!PageUtilitiesExtended.HasDirectNavigationPageParent(currentPage))
            {
                throw new InvalidOperationException("Removing views using the relative '../' syntax while navigating is only supported within a NavigationPage");
            }

            if (CanRemoveAndPush(segments))
            {
                return(RemoveAndPush(currentPage, nextSegment, segments, parameters, useModalNavigation, animated));
            }
            else
            {
                return(RemoveAndGoBack(currentPage, nextSegment, segments, parameters, useModalNavigation, animated));
            }
        }
        internal static bool UseModalNavigation(Page currentPage, bool?useModalNavigationDefault)
        {
            bool useModalNavigation = true;

            if (useModalNavigationDefault.HasValue)
            {
                useModalNavigation = useModalNavigationDefault.Value;
            }
            else if (currentPage is NavigationPage)
            {
                useModalNavigation = false;
            }
            else
            {
                useModalNavigation = !PageUtilitiesExtended.HasNavigationPageParent(currentPage);
            }

            return(useModalNavigation);
        }
        protected virtual Page CreatePageFromSegment(string segment)
        {
            try
            {
                var segmentName = UriParsingHelper.GetSegmentName(segment);
                var page        = CreatePage(segmentName);
                if (page == null)
                {
                    throw new NullReferenceException(string.Format("{0} could not be created. Please make sure you have registered {0} for navigation.", segmentName));
                }

                PageUtilitiesExtended.SetAutowireViewModelOnPage(page);
                _pageBehaviorFactory.ApplyPageBehaviors(page);
                ConfigurePages(page, segment);

                return(page);
            }
            catch (Exception e)
            {
                _logger.Log(e.ToString(), Category.Exception, Priority.High);
                throw;
            }
        }
        protected virtual async Task UseReverseNavigation(Page currentPage, string nextSegment, Queue <string> segments, INavigationParameters parameters, bool?useModalNavigation, bool animated)
        {
            var navigationStack = new Stack <string>();

            if (!String.IsNullOrWhiteSpace(nextSegment))
            {
                navigationStack.Push(nextSegment);
            }

            var illegalSegments = new Queue <string>();

            bool illegalPageFound = false;

            foreach (var item in segments)
            {
                //if we run into an illegal page, we need to create new navigation segments to properly handle the deep link
                if (illegalPageFound)
                {
                    illegalSegments.Enqueue(item);
                    continue;
                }

                //if any page decide to go modal, we need to consider it and all pages after it an illegal page
                var pageParameters = UriParsingHelper.GetSegmentParameters(item);
                if (pageParameters.ContainsKey(KnownNavigationParameters.UseModalNavigation))
                {
                    if (pageParameters.GetValue <bool>(KnownNavigationParameters.UseModalNavigation))
                    {
                        illegalSegments.Enqueue(item);
                        illegalPageFound = true;
                    }
                    else
                    {
                        navigationStack.Push(item);
                    }
                }
                else
                {
                    var pageType = PageNavigationRegistry.GetPageType(UriParsingHelper.GetSegmentName(item));
                    if (PageUtilitiesExtended.IsSameOrSubclassOf <MasterDetailPage>(pageType))
                    {
                        illegalSegments.Enqueue(item);
                        illegalPageFound = true;
                    }
                    else
                    {
                        navigationStack.Push(item);
                    }
                }
            }

            var pageOffset = currentPage.Navigation.NavigationStack.Count;

            if (currentPage.Navigation.NavigationStack.Count > 2)
            {
                pageOffset = currentPage.Navigation.NavigationStack.Count - 1;
            }

            var onNavigatedFromTarget = currentPage;

            if (currentPage is NavigationPage navPage && navPage.CurrentPage != null)
            {
                onNavigatedFromTarget = navPage.CurrentPage;
            }

            bool insertBefore = false;

            while (navigationStack.Count > 0)
            {
                var segment  = navigationStack.Pop();
                var nextPage = CreatePageFromSegment(segment);
                await DoNavigateAction(onNavigatedFromTarget, segment, nextPage, parameters, async() =>
                {
                    await DoPush(currentPage, nextPage, useModalNavigation, animated, insertBefore, pageOffset);
                });

                insertBefore = true;
            }

            //if an illegal page is found, we force a Modal navigation
            if (illegalSegments.Count > 0)
            {
                await ProcessNavigation(currentPage.Navigation.NavigationStack.Last(), illegalSegments, parameters, true, animated);
            }
        }
 internal static bool UseReverseNavigation(Page currentPage, Type nextPageType)
 {
     return(PageUtilitiesExtended.HasNavigationPageParent(currentPage) && PageUtilitiesExtended.IsSameOrSubclassOf <ContentPage>(nextPageType));
 }