internal void NavigateToShellSection(ShellNavigationSource source, ShellSection section, bool animate = true)
        {
            _ = section ?? throw new ArgumentNullException(nameof(section));

            if (ShellSection != null)
            {
                ShellSection.PropertyChanged -= OnShellSectionPropertyChanged;
                ((System.Collections.Specialized.INotifyCollectionChanged)section.Items).CollectionChanged -= OnShellSectionRendererCollectionChanged;
                ShellSection    = null;
                MenuItemsSource = null;
            }

            ShellSection = section;
            ShellSection.PropertyChanged += OnShellSectionPropertyChanged;
            SelectedItem    = null;
            IsPaneVisible   = section.Items.Count > 1;
            MenuItemsSource = section.Items;
            ((System.Collections.Specialized.INotifyCollectionChanged)section.Items).CollectionChanged += OnShellSectionRendererCollectionChanged;
            SelectedItem = section.CurrentItem;
            NavigateToContent(source, section.CurrentItem, animate);
        }
Esempio n. 2
0
        // This is used for cases where the user is navigating via native UI navigation i.e. clicking on Tabs
        // If the user defers this type of navigation we generate the equivalent GotoAsync call
        // so when the deferral is completed the same navigation can complete
        public bool ProposeNavigationOutsideGotoAsync(
            ShellNavigationSource source,
            ShellItem shellItem,
            ShellSection shellSection,
            ShellContent shellContent,
            IReadOnlyList <Page> stack,
            bool canCancel,
            bool isAnimated)
        {
            if (AccumulateNavigatedEvents)
            {
                return(true);
            }

            var proposedState = GetNavigationState(shellItem, shellSection, shellContent, stack, shellSection.Navigation.ModalStack);
            var navArgs       = ProposeNavigation(source, proposedState, canCancel, isAnimated);

            if (navArgs.DeferralCount > 0)
            {
                navArgs.RegisterDeferralCompletedCallBack(async() =>
                {
                    if (navArgs.Cancelled)
                    {
                        return;
                    }

                    Func <Task> navigationTask = () => GoToAsync(navArgs.Target, navArgs.Animate, false, navArgs);

                    await _shell
                    .FindDispatcher()
                    .DispatchIfRequiredAsync(navigationTask);
                });
            }

            return(!navArgs.NavigationDelayedOrCancelled);
        }
Esempio n. 3
0
        /// <include file="../../../docs/Microsoft.Maui.Controls/ShellNavigatingEventArgs.xml" path="//Member[@MemberName='.ctor']/Docs" />
        public ShellNavigatingEventArgs(ShellNavigationState current, ShellNavigationState target, ShellNavigationSource source, bool canCancel)
        {
#if !NETSTANDARD1_0
            _deferralFinishedTask = () => Task.CompletedTask;
#else
            _deferralFinishedTask = () => Task.Delay(0);
#endif
            Current   = current;
            Target    = target;
            Source    = source;
            CanCancel = canCancel;
            Animate   = true;
        }
Esempio n. 4
0
 protected override void SetupAnimation(ShellNavigationSource navSource, AndroidX.Fragment.App.FragmentTransaction t, Page page)
 {
     // Don't setup any animations
 }
Esempio n. 5
0
 public void TestNavigationArgs(ShellNavigationSource source, string from, string to)
 {
     TestNavigatingArgs(source, from, to);
     TestNavigatedArgs(source, from, to);
 }
Esempio n. 6
0
        internal async Task GoToAsync(
            ShellNavigationParameters shellNavigationParameters,
            ShellNavigationRequest navigationRequest)
        {
            // check for any pending navigations that need to complete
            if (_shell?.CurrentItem?.CurrentItem?.PendingNavigationTask != null)
            {
                await(_shell?.CurrentItem?.CurrentItem?.PendingNavigationTask ?? Task.CompletedTask);
            }

            if (shellNavigationParameters.PagePushing != null && navigationRequest == null)
            {
                Routing.RegisterImplicitPageRoute(shellNavigationParameters.PagePushing);
            }

            var  state   = shellNavigationParameters.TargetState ?? new ShellNavigationState(Routing.GetRoute(shellNavigationParameters.PagePushing), false);
            bool?animate = shellNavigationParameters.Animated;
            bool enableRelativeShellRoutes        = shellNavigationParameters.EnableRelativeShellRoutes;
            ShellNavigatingEventArgs deferredArgs = shellNavigationParameters.DeferredArgs;

            navigationRequest ??= ShellUriHandler.GetNavigationRequest(_shell, state.FullLocation, enableRelativeShellRoutes, shellNavigationParameters: shellNavigationParameters);

            bool isRelativePopping = ShellUriHandler.IsTargetRelativePop(shellNavigationParameters);
            var  parameters        = shellNavigationParameters.Parameters ?? new ShellRouteParameters();

            ShellNavigationSource source = CalculateNavigationSource(_shell, _shell.CurrentState, navigationRequest);

            // If the deferredArgs are non null that means we are processing a delayed navigation
            // so the user has indicated they want to go forward with navigation
            // This scenario only comes up from UI iniated navigation (i.e. switching tabs)
            if (deferredArgs == null)
            {
                var navigatingArgs = ProposeNavigation(source, state, _shell.CurrentState != null, animate ?? true);

                if (navigatingArgs != null)
                {
                    bool accept = !navigatingArgs.NavigationDelayedOrCancelled;
                    if (navigatingArgs.DeferredTask != null)
                    {
                        accept = await navigatingArgs.DeferredTask;
                    }

                    if (!accept)
                    {
                        return;
                    }
                }
            }

            Routing.RegisterImplicitPageRoutes(_shell);

            _accumulateNavigatedEvents = true;

            var uri         = navigationRequest.Request.FullUri;
            var queryString = navigationRequest.Query;
            var queryData   = ParseQueryString(queryString);

            parameters.Merge(queryData);
            ApplyQueryAttributes(_shell, parameters, false, false);

            var shellItem           = navigationRequest.Request.Item;
            var shellSection        = navigationRequest.Request.Section;
            var currentShellSection = _shell.CurrentItem?.CurrentItem;
            var nextActiveSection   = shellSection ?? shellItem?.CurrentItem;

            ShellContent shellContent       = navigationRequest.Request.Content;
            bool         modalStackPreBuilt = false;

            // check for any pending navigations that need to complete
            if (currentShellSection?.PendingNavigationTask != null)
            {
                await(currentShellSection?.PendingNavigationTask ?? Task.CompletedTask);
            }

            // If we're replacing the whole stack and there are global routes then build the navigation stack before setting the shell section visible
            if (navigationRequest.Request.GlobalRoutes.Count > 0 &&
                nextActiveSection != null &&
                navigationRequest.StackRequest == ShellNavigationRequest.WhatToDoWithTheStack.ReplaceIt)
            {
                modalStackPreBuilt = true;

                bool?isAnimated = (nextActiveSection != currentShellSection) ? false : animate;
                await nextActiveSection.GoToAsync(navigationRequest, parameters, _shell.FindMauiContext()?.Services, isAnimated, isRelativePopping);
            }

            if (shellItem != null)
            {
                ApplyQueryAttributes(shellItem, parameters, navigationRequest.Request.Section == null, false);
                bool navigatedToNewShellElement = false;

                if (shellSection != null && shellContent != null)
                {
                    ApplyQueryAttributes(shellContent, parameters, navigationRequest.Request.GlobalRoutes.Count == 0, isRelativePopping);
                    if (shellSection.CurrentItem != shellContent)
                    {
                        shellSection.SetValueFromRenderer(ShellSection.CurrentItemProperty, shellContent);
                        navigatedToNewShellElement = true;
                    }
                }

                if (shellSection != null)
                {
                    ApplyQueryAttributes(shellSection, parameters, navigationRequest.Request.Content == null, false);
                    if (shellItem.CurrentItem != shellSection)
                    {
                        shellItem.SetValueFromRenderer(ShellItem.CurrentItemProperty, shellSection);
                        navigatedToNewShellElement = true;
                    }
                }

                if (_shell.CurrentItem != shellItem)
                {
                    _shell.SetValueFromRenderer(Shell.CurrentItemProperty, shellItem);
                    navigatedToNewShellElement = true;
                }

                // Setting the current item isn't an async operation but it triggers an async
                // navigation path. So this waits until that's finished before returning from GotoAsync
                if (_shell?.CurrentItem?.CurrentItem?.PendingNavigationTask != null)
                {
                    await(_shell?.CurrentItem?.CurrentItem?.PendingNavigationTask ?? Task.CompletedTask);
                }

                if (!modalStackPreBuilt && currentShellSection?.Navigation.ModalStack.Count > 0)
                {
                    // - navigating to new shell element so just pop everything
                    // - or route contains no global route requests
                    if (navigatedToNewShellElement || navigationRequest.Request.GlobalRoutes.Count == 0)
                    {
                        // remove all non visible pages first so the transition just smoothly goes from
                        // currently visible modal to base page
                        if (navigationRequest.Request.GlobalRoutes.Count == 0)
                        {
                            for (int i = currentShellSection.Stack.Count - 1; i >= 1; i--)
                            {
                                currentShellSection.Navigation.RemovePage(currentShellSection.Stack[i]);
                            }
                        }

                        await currentShellSection.PopModalStackToPage(null, animate);
                    }
                }

                if (navigationRequest.Request.GlobalRoutes.Count > 0 && navigationRequest.StackRequest != ShellNavigationRequest.WhatToDoWithTheStack.ReplaceIt)
                {
                    // TODO get rid of this hack and fix so if there's a stack the current page doesn't display
                    await _shell.Dispatcher.DispatchAsync(() =>
                    {
                        return(_shell.CurrentItem.CurrentItem.GoToAsync(navigationRequest, parameters, _shell.FindMauiContext()?.Services, animate, isRelativePopping));
                    });
                }
                else if (navigationRequest.Request.GlobalRoutes.Count == 0 &&
                         navigationRequest.StackRequest == ShellNavigationRequest.WhatToDoWithTheStack.ReplaceIt &&
                         nextActiveSection?.Navigation?.NavigationStack?.Count > 1)
                {
                    // TODO get rid of this hack and fix so if there's a stack the current page doesn't display
                    await _shell.Dispatcher.DispatchAsync(() =>
                    {
                        return(_shell.CurrentItem.CurrentItem.GoToAsync(navigationRequest, parameters, _shell.FindMauiContext()?.Services, animate, isRelativePopping));
                    });
                }
            }
            else
            {
                await _shell.CurrentItem.CurrentItem.GoToAsync(navigationRequest, parameters, _shell.FindMauiContext()?.Services, animate, isRelativePopping);
            }

            // Setting the current item isn't an async operation but it triggers an async
            // navigation path. So this waits until that's finished before returning from GotoAsync
            if (_shell?.CurrentItem?.CurrentItem?.PendingNavigationTask != null)
            {
                await(_shell?.CurrentItem?.CurrentItem?.PendingNavigationTask ?? Task.CompletedTask);
            }

            (_shell as IShellController).UpdateCurrentState(source);
            _accumulateNavigatedEvents = false;

            // this can be null in the event that no navigation actually took place!
            if (_accumulatedEvent != null)
            {
                HandleNavigated(_accumulatedEvent);
            }
        }
Esempio n. 7
0
 public ShellNavigatedEventArgs(ShellNavigationState previous, ShellNavigationState current, ShellNavigationSource source)
 {
     Previous = previous;
     Current  = current;
     Source   = source;
 }
Esempio n. 8
0
        internal void NavigateToContent(ShellNavigationSource source, ShellContent shellContent, Page page, bool animate = true)
        {
            Page nextPage = null;

            if (source == ShellNavigationSource.PopToRoot)
            {
                nextPage = (shellContent as IShellContentController).GetOrCreateContent();
            }
            else
            {
                nextPage = (ShellSection as IShellSectionController)
                           .PresentedPage ?? ((IShellContentController)shellContent)?.GetOrCreateContent();
            }

            if (CurrentContent != null && Page != null)
            {
                Page.PropertyChanged -= OnPagePropertyChanged;
                ((IShellContentController)CurrentContent).RecyclePage(Page);
            }

            CurrentContent = shellContent;
            if (nextPage != null)
            {
                Page = nextPage;
                Page.PropertyChanged += OnPagePropertyChanged;
                switch (source)
                {
                case ShellNavigationSource.Insert:
                {
                    var pageIndex = ShellSection.Stack.ToList().IndexOf(page);
                    if (pageIndex == Frame.BackStack.Count - 1)
                    {
                        Frame.Navigate(typeof(ShellPageWrapper), GetTransitionInfo(source));
                    }
                    else
                    {
                        Frame.BackStack.Insert(pageIndex, new PageStackEntry(typeof(ShellPageWrapper), null, GetTransitionInfo(source)));
                    }
                    break;
                }

                case ShellNavigationSource.Pop:
                    Frame.GoBack(GetTransitionInfo(source));
                    break;

                case ShellNavigationSource.Unknown:
                    break;

                case ShellNavigationSource.Push:
                    Frame.Navigate(typeof(ShellPageWrapper), GetTransitionInfo(source));
                    break;

                case ShellNavigationSource.PopToRoot:
                    while (Frame.BackStackDepth > 2)
                    {
                        Frame.BackStack.RemoveAt(1);
                    }
                    Frame.GoBack(GetTransitionInfo(source));
                    break;

                case ShellNavigationSource.Remove:
                {
                    var pageIndex = FormsNavigationStack.IndexOf(page);
                    if (pageIndex == Frame.BackStack.Count - 1)
                    {
                        Frame.GoBack(GetTransitionInfo(source));
                    }
                    else
                    {
                        Frame.BackStack.RemoveAt(pageIndex);
                    }
                    break;
                }

                case ShellNavigationSource.ShellItemChanged:
                    break;

                case ShellNavigationSource.ShellSectionChanged:
                    Frame.Navigate(typeof(ShellPageWrapper), GetTransitionInfo(source));
                    break;

                case ShellNavigationSource.ShellContentChanged:
                    break;
                }

                UpdateSearchHandler(Shell.GetSearchHandler(Page));
                var wrapper = (ShellPageWrapper)(Frame.Content);
                if (wrapper.Page == null)
                {
                    wrapper.Page = Page;
                }

                wrapper.LoadPage();
                FormsNavigationStack = ShellSection.Stack.ToList();
            }
        }
Esempio n. 9
0
 public ShellNavigatingEventArgs(ShellNavigationState current, ShellNavigationState target, ShellNavigationSource source, bool canCancel)
 {
     Current   = current;
     Target    = target;
     Source    = source;
     CanCancel = canCancel;
 }
Esempio n. 10
0
 /// <include file="../../../docs/Microsoft.Maui.Controls/ShellNavigatingEventArgs.xml" path="//Member[@MemberName='.ctor']/Docs" />
 public ShellNavigatingEventArgs(ShellNavigationState current, ShellNavigationState target, ShellNavigationSource source, bool canCancel)
 {
     _deferralFinishedTask = () => Task.CompletedTask;
     Current   = current;
     Target    = target;
     Source    = source;
     CanCancel = canCancel;
     Animate   = true;
 }
Esempio n. 11
0
        internal void NavigateToContent(ShellNavigationSource source, ShellContent shellContent, Page page, bool animate = true)
        {
            Page nextPage = (ShellSection as IShellSectionController)
                            .PresentedPage ?? ((IShellContentController)shellContent)?.GetOrCreateContent();

            if (CurrentContent != null && Page != null)
            {
                Page.PropertyChanged -= OnPagePropertyChanged;
                ((IShellContentController)CurrentContent).RecyclePage(Page);
            }

            CurrentContent = shellContent;
            if (nextPage != null)
            {
                Page = nextPage;
                Page.PropertyChanged += OnPagePropertyChanged;
                switch (source)
                {
                case ShellNavigationSource.Insert:
                    break;

                case ShellNavigationSource.Pop:
                    Frame.GoBack(GetTransitionInfo(source));
                    break;

                case ShellNavigationSource.Unknown:
                    break;

                case ShellNavigationSource.Push:
                    Frame.Navigate(typeof(ShellPageWrapper), GetTransitionInfo(source));
                    break;

                case ShellNavigationSource.PopToRoot:
                    while (Frame.BackStackDepth > 1)
                    {
                        Frame.GoBack(GetTransitionInfo(source));
                    }
                    break;

                case ShellNavigationSource.Remove:
                    break;

                case ShellNavigationSource.ShellItemChanged:
                    break;

                case ShellNavigationSource.ShellSectionChanged:
                    Frame.Navigate(typeof(ShellPageWrapper), GetTransitionInfo(source));
                    break;

                case ShellNavigationSource.ShellContentChanged:
                    break;
                }

                UpdateSearchHandler(Shell.GetSearchHandler(Page));
                var wrapper = (ShellPageWrapper)(Frame.Content);
                if (wrapper.Page == null)
                {
                    wrapper.Page = Page;
                }

                wrapper.LoadPage();
            }
        }