Exemple #1
0
        static IEnumerable GetItems(object node)
        {
            IEnumerable results = null;

            switch (node)
            {
            case IShellController shell:
                results = shell.GetItems();
                break;

            case IShellItemController item:
                results = item.GetItems();
                break;

            case IShellSectionController section:
                results = section.GetItems();
                break;

            case ShellContent content:
                results = new object[0];
                break;

            case GlobalRouteItem routeItem:
                results = routeItem.Items;
                break;
            }

            if (results == null)
            {
                throw new ArgumentException($"{node}", nameof(node));
            }

            foreach (var result in results)
            {
                yield return(result);
            }

            if (node is GlobalRouteItem)
            {
                yield break;
            }

            var    keys  = Routing.GetRouteKeys();
            string route = GetRoute(node);

            for (var i = 0; i < keys.Length; i++)
            {
                var key = FormatUri(keys[i]);
                if (key.StartsWith(_pathSeparator, StringComparison.Ordinal) && !(node is Shell))
                {
                    continue;
                }

                var segments = key.Split(_pathSeparator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

                if (segments[0] == route)
                {
                    yield return(new GlobalRouteItem(key, key));
                }
            }
        }
Exemple #2
0
        internal static List <RouteRequestBuilder> GenerateRoutePaths(Shell shell, Uri request, Uri originalRequest, bool enableRelativeShellRoutes)
        {
            var routeKeys = Routing.GetRouteKeys();

            for (int i = 0; i < routeKeys.Length; i++)
            {
                if (routeKeys[i] == originalRequest.OriginalString)
                {
                    var builder = new RouteRequestBuilder(routeKeys[i], routeKeys[i], null, new string[] { routeKeys[i] });
                    return(new List <RouteRequestBuilder> {
                        builder
                    });
                }
                routeKeys[i] = FormatUri(routeKeys[i]);
            }

            request         = FormatUri(request, shell);
            originalRequest = FormatUri(originalRequest, shell);

            List <RouteRequestBuilder> possibleRoutePaths = new List <RouteRequestBuilder>();

            if (!request.IsAbsoluteUri)
            {
                request = ConvertToStandardFormat(shell, request);
            }

            string localPath = request.LocalPath;

            bool relativeMatch = false;

            if (!originalRequest.IsAbsoluteUri &&
                !originalRequest.OriginalString.StartsWith("//", StringComparison.Ordinal))
            {
                relativeMatch = true;
            }

            var segments = localPath.Split(_pathSeparator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

            if (!relativeMatch)
            {
                for (int i = 0; i < routeKeys.Length; i++)
                {
                    var route = routeKeys[i];
                    var uri   = ConvertToStandardFormat(shell, CreateUri(route));
                    if (uri.Equals(request))
                    {
                        throw new Exception($"Global routes currently cannot be the only page on the stack, so absolute routing to global routes is not supported. For now, just navigate to: {originalRequest.OriginalString.Replace("//", "")}");
                        //var builder = new RouteRequestBuilder(route, route, null, segments);
                        //return new List<RouteRequestBuilder> { builder };
                    }
                }
            }

            var depthStart = 0;

            if (segments[0] == shell?.Route)
            {
                segments   = segments.Skip(1).ToArray();
                depthStart = 1;
            }
            else
            {
                depthStart = 0;
            }

            if (relativeMatch && shell?.CurrentItem != null)
            {
                // retrieve current location
                var currentLocation = NodeLocation.Create(shell);

                while (currentLocation.Shell != null)
                {
                    var pureRoutesMatch       = new List <RouteRequestBuilder>();
                    var pureGlobalRoutesMatch = new List <RouteRequestBuilder>();

                    //currently relative routes to shell routes isn't supported as we aren't creating navigation stacks
                    if (enableRelativeShellRoutes)
                    {
                        SearchPath(currentLocation.LowestChild, null, segments, pureRoutesMatch, 0);
                        ExpandOutGlobalRoutes(pureRoutesMatch, routeKeys);
                        pureRoutesMatch = GetBestMatches(pureRoutesMatch);
                        if (pureRoutesMatch.Count > 0)
                        {
                            return(pureRoutesMatch);
                        }
                    }


                    SearchPath(currentLocation.LowestChild, null, segments, pureGlobalRoutesMatch, 0, ignoreGlobalRoutes: false);
                    ExpandOutGlobalRoutes(pureGlobalRoutesMatch, routeKeys);
                    pureGlobalRoutesMatch = GetBestMatches(pureGlobalRoutesMatch);
                    if (pureGlobalRoutesMatch.Count > 0)
                    {
                        // currently relative routes to shell routes isn't supported as we aren't creating navigation stacks
                        // So right now we will just throw an exception so that once this is implemented
                        // GotoAsync doesn't start acting inconsistently and all of a sudden starts creating routes

                        int shellElementsMatched =
                            pureGlobalRoutesMatch[0].SegmentsMatched.Count -
                            pureGlobalRoutesMatch[0].GlobalRouteMatches.Count;

                        if (!enableRelativeShellRoutes && shellElementsMatched > 0)
                        {
                            throw new Exception($"Relative routing to shell elements is currently not supported. Try prefixing your uri with ///: ///{originalRequest}");
                        }

                        return(pureGlobalRoutesMatch);
                    }

                    currentLocation.Pop();
                }

                string searchPath = String.Join(_pathSeparator, segments);

                if (routeKeys.Contains(searchPath))
                {
                    return(new List <RouteRequestBuilder> {
                        new RouteRequestBuilder(searchPath, searchPath, null, segments)
                    });
                }

                RouteRequestBuilder builder = null;
                foreach (var segment in segments)
                {
                    if (routeKeys.Contains(segment))
                    {
                        if (builder == null)
                        {
                            builder = new RouteRequestBuilder(segment, segment, null, segments);
                        }
                        else
                        {
                            builder.AddGlobalRoute(segment, segment);
                        }
                    }
                }

                if (builder != null && builder.IsFullMatch)
                {
                    return new List <RouteRequestBuilder> {
                               builder
                    }
                }
                ;
            }
            else
            {
                possibleRoutePaths.Clear();
                SearchPath(shell, null, segments, possibleRoutePaths, depthStart);

                var bestMatches = GetBestMatches(possibleRoutePaths);
                if (bestMatches.Count > 0)
                {
                    return(bestMatches);
                }

                bestMatches.Clear();
                ExpandOutGlobalRoutes(possibleRoutePaths, routeKeys);
            }

            possibleRoutePaths = GetBestMatches(possibleRoutePaths);
            return(possibleRoutePaths);
        }
Exemple #3
0
        static void SearchPath(
            object node,
            RouteRequestBuilder currentMatchedPath,
            string[] segments,
            List <RouteRequestBuilder> possibleRoutePaths,
            int depthToStart,
            int myDepth = -1,
            NodeLocation currentLocation = null,
            bool ignoreGlobalRoutes      = true)
        {
            if (node is GlobalRouteItem && ignoreGlobalRoutes)
            {
                return;
            }

            ++myDepth;
            currentLocation = currentLocation ?? new NodeLocation();
            currentLocation.SetNode(node);

            IEnumerable items = null;

            if (depthToStart > myDepth)
            {
                items = GetItems(node);
                if (items == null)
                {
                    return;
                }

                foreach (var nextNode in items)
                {
                    SearchPath(nextNode, null, segments, possibleRoutePaths, depthToStart, myDepth, currentLocation, ignoreGlobalRoutes);
                }
                return;
            }

            string shellSegment = GetRoute(node);
            string userSegment  = null;

            if (currentMatchedPath == null)
            {
                userSegment = segments[0];
            }
            else
            {
                userSegment = currentMatchedPath.NextSegment;
            }

            if (userSegment == null)
            {
                return;
            }

            RouteRequestBuilder builder = null;

            if (shellSegment == userSegment || Routing.IsImplicit(shellSegment))
            {
                if (currentMatchedPath == null)
                {
                    builder = new RouteRequestBuilder(shellSegment, userSegment, node, segments);
                }
                else
                {
                    builder = new RouteRequestBuilder(currentMatchedPath);
                    builder.AddMatch(shellSegment, userSegment, node);
                }

                if (!Routing.IsImplicit(shellSegment) || shellSegment == userSegment)
                {
                    possibleRoutePaths.Add(builder);
                }
            }

            items = GetItems(node);
            if (items == null)
            {
                return;
            }

            foreach (var nextNode in items)
            {
                SearchPath(nextNode, builder, segments, possibleRoutePaths, depthToStart, myDepth, currentLocation, ignoreGlobalRoutes);
            }
        }
        internal static List <RouteRequestBuilder> GenerateRoutePaths(Shell shell, Uri request, Uri originalRequest)
        {
            request         = FormatUri(request);
            originalRequest = FormatUri(originalRequest);

            var routeKeys = Routing.GetRouteKeys();

            for (int i = 0; i < routeKeys.Length; i++)
            {
                routeKeys[i] = FormatUri(routeKeys[i]);
            }

            List <RouteRequestBuilder> possibleRoutePaths = new List <RouteRequestBuilder>();

            if (!request.IsAbsoluteUri)
            {
                request = ConvertToStandardFormat(shell, request);
            }

            string localPath = request.LocalPath;

            bool relativeMatch = false;

            if (!originalRequest.IsAbsoluteUri && !originalRequest.OriginalString.StartsWith("/") && !originalRequest.OriginalString.StartsWith("\\"))
            {
                relativeMatch = true;
            }

            var segments = localPath.Split(_pathSeparator, StringSplitOptions.RemoveEmptyEntries);

            if (!relativeMatch)
            {
                for (int i = 0; i < routeKeys.Length; i++)
                {
                    var route = routeKeys[i];
                    var uri   = ConvertToStandardFormat(shell, new Uri(route, UriKind.RelativeOrAbsolute));
                    // Todo is this supported?
                    if (uri.Equals(request))
                    {
                        var builder = new RouteRequestBuilder(route, route, null, segments);
                        return(new List <RouteRequestBuilder> {
                            builder
                        });
                    }
                }
            }

            var depthStart = 0;

            if (segments[0] == shell.Route)
            {
                segments   = segments.Skip(1).ToArray();
                depthStart = 1;
            }
            else
            {
                depthStart = 0;
            }

            if (relativeMatch && shell?.CurrentItem != null)
            {
                // retrieve current location
                var currentLocation = NodeLocation.Create(shell);

                while (currentLocation.Shell != null)
                {
                    List <RouteRequestBuilder> pureRoutesMatch       = new List <RouteRequestBuilder>();
                    List <RouteRequestBuilder> pureGlobalRoutesMatch = new List <RouteRequestBuilder>();

                    SearchPath(currentLocation.LowestChild, null, segments, pureRoutesMatch, 0);
                    SearchPath(currentLocation.LowestChild, null, segments, pureGlobalRoutesMatch, 0, ignoreGlobalRoutes: false);
                    pureRoutesMatch       = GetBestMatches(pureRoutesMatch);
                    pureGlobalRoutesMatch = GetBestMatches(pureGlobalRoutesMatch);

                    if (pureRoutesMatch.Count > 0)
                    {
                        return(pureRoutesMatch);
                    }

                    if (pureGlobalRoutesMatch.Count > 0)
                    {
                        return(pureGlobalRoutesMatch);
                    }

                    currentLocation.Pop();
                }

                string searchPath = String.Join("/", segments);

                if (routeKeys.Contains(searchPath))
                {
                    return(new List <RouteRequestBuilder> {
                        new RouteRequestBuilder(searchPath, searchPath, null, segments)
                    });
                }

                RouteRequestBuilder builder = null;
                foreach (var segment in segments)
                {
                    if (routeKeys.Contains(segment))
                    {
                        if (builder == null)
                        {
                            builder = new RouteRequestBuilder(segment, segment, null, segments);
                        }
                        else
                        {
                            builder.AddGlobalRoute(segment, segment);
                        }
                    }
                }

                if (builder != null && builder.IsFullMatch)
                {
                    return new List <RouteRequestBuilder> {
                               builder
                    }
                }
                ;
            }
            else
            {
                possibleRoutePaths.Clear();
                SearchPath(shell, null, segments, possibleRoutePaths, depthStart);

                var bestMatches = GetBestMatches(possibleRoutePaths);
                if (bestMatches.Count > 0)
                {
                    return(bestMatches);
                }

                bestMatches.Clear();
                foreach (var possibleRoutePath in possibleRoutePaths)
                {
                    while (routeKeys.Contains(possibleRoutePath.NextSegment) || routeKeys.Contains(possibleRoutePath.RemainingPath))
                    {
                        if (routeKeys.Contains(possibleRoutePath.NextSegment))
                        {
                            possibleRoutePath.AddGlobalRoute(possibleRoutePath.NextSegment, possibleRoutePath.NextSegment);
                        }
                        else
                        {
                            possibleRoutePath.AddGlobalRoute(possibleRoutePath.RemainingPath, possibleRoutePath.RemainingPath);
                        }
                    }

                    while (!possibleRoutePath.IsFullMatch)
                    {
                        NodeLocation nodeLocation = new NodeLocation();
                        nodeLocation.SetNode(possibleRoutePath.LowestChild);
                        List <RouteRequestBuilder> pureGlobalRoutesMatch = new List <RouteRequestBuilder>();
                        while (nodeLocation.Shell != null && pureGlobalRoutesMatch.Count == 0)
                        {
                            SearchPath(nodeLocation.LowestChild, null, possibleRoutePath.RemainingSegments, pureGlobalRoutesMatch, 0, ignoreGlobalRoutes: false);
                            nodeLocation.Pop();
                        }

                        // nothing found or too many things found
                        if (pureGlobalRoutesMatch.Count != 1)
                        {
                            break;
                        }


                        for (var i = 0; i < pureGlobalRoutesMatch[0].GlobalRouteMatches.Count; i++)
                        {
                            var match = pureGlobalRoutesMatch[0];
                            possibleRoutePath.AddGlobalRoute(match.GlobalRouteMatches[i], match.SegmentsMatched[i]);
                        }
                    }
                }
            }

            possibleRoutePaths = GetBestMatches(possibleRoutePaths);
            return(possibleRoutePaths);
        }
Exemple #5
0
        bool UpdateFlyoutGroupings()
        {
            // The idea here is to create grouping such that the Flyout would
            // render correctly if it renderered each item in the groups in order
            // but put a line between the groups. This is needed because our grouping can
            // actually go 3 layers deep.

            // Ideally this lets us control where lines are drawn in the core code
            // just by changing how we generate these groupings

            var result = new List <List <Element> >();

            var currentGroup = new List <Element>();

            foreach (var shellItem in ShellController.GetItems())
            {
                if (!ShowInFlyoutMenu(shellItem))
                {
                    continue;
                }

                if (Routing.IsImplicit(shellItem) || shellItem.FlyoutDisplayOptions == FlyoutDisplayOptions.AsMultipleItems)
                {
                    if (shellItem.FlyoutDisplayOptions == FlyoutDisplayOptions.AsMultipleItems)
                    {
                        IncrementGroup();
                    }

                    foreach (var shellSection in (shellItem as IShellItemController).GetItems())
                    {
                        if (!ShowInFlyoutMenu(shellSection))
                        {
                            continue;
                        }

                        var shellContents = ((IShellSectionController)shellSection).GetItems();
                        if (Routing.IsImplicit(shellSection) || shellSection.FlyoutDisplayOptions == FlyoutDisplayOptions.AsMultipleItems)
                        {
                            foreach (var shellContent in shellContents)
                            {
                                if (!ShowInFlyoutMenu(shellContent))
                                {
                                    continue;
                                }

                                currentGroup.Add(shellContent);
                                if (shellContent == shellSection.CurrentItem)
                                {
                                    AddMenuItems(shellContent.MenuItems);
                                }
                            }

                            if (shellSection.FlyoutDisplayOptions == FlyoutDisplayOptions.AsMultipleItems)
                            {
                                IncrementGroup();
                            }
                        }
                        else
                        {
                            if (!(shellSection.Parent is TabBar))
                            {
                                if (Routing.IsImplicit(shellSection) && shellContents.Count == 1)
                                {
                                    if (!ShowInFlyoutMenu(shellContents[0]))
                                    {
                                        continue;
                                    }

                                    currentGroup.Add(shellContents[0]);
                                }
                                else
                                {
                                    currentGroup.Add(shellSection);
                                }
                            }

                            // If we have only a single child we will also show the items menu items
                            if (shellContents.Count == 1 && shellSection == shellItem.CurrentItem && shellSection.CurrentItem.MenuItems.Count > 0)
                            {
                                AddMenuItems(shellSection.CurrentItem.MenuItems);
                            }
                        }
                    }

                    if (shellItem.FlyoutDisplayOptions == FlyoutDisplayOptions.AsMultipleItems)
                    {
                        IncrementGroup();
                    }
                }
                else
                {
                    if (!(shellItem is TabBar))
                    {
                        currentGroup.Add(shellItem);
                    }
                }
            }

            IncrementGroup();

            // If the flyout groupings haven't changed just return
            // the same instance so the caller knows it hasn't changed
            // at a later point this will all get converted to an observable collection
            if (_lastGeneratedFlyoutItems?.Count == result.Count)
            {
                bool hasChanged = false;
                for (var i = 0; i < result.Count && !hasChanged; i++)
                {
                    var topLevelNew      = result[i];
                    var topLevelPrevious = _lastGeneratedFlyoutItems[i];

                    if (topLevelNew.Count != topLevelPrevious.Count)
                    {
                        hasChanged = true;
                        break;
                    }

                    for (var j = 0; j > topLevelNew.Count; j++)
                    {
                        if (topLevelNew[j] != topLevelPrevious[j])
                        {
                            hasChanged = true;
                            break;
                        }
                    }
                }

                if (!hasChanged)
                {
                    return(false);
                }
            }

            _lastGeneratedFlyoutItems = result;
            return(true);

            bool ShowInFlyoutMenu(BindableObject bo)
            {
                if (bo is MenuShellItem msi)
                {
                    return(Shell.GetFlyoutItemIsVisible(msi.MenuItem));
                }

                return(Shell.GetFlyoutItemIsVisible(bo));
            }

            void AddMenuItems(MenuItemCollection menuItems)
            {
                foreach (var item in menuItems)
                {
                    if (ShowInFlyoutMenu(item))
                    {
                        currentGroup.Add(item);
                    }
                }
            }

            void IncrementGroup()
            {
                if (currentGroup.Count > 0)
                {
                    result.Add(currentGroup);
                    currentGroup = new List <Element>();
                }
            }
        }
Exemple #6
0
        public void AddMatch(string shellSegment, string userSegment, object node)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            switch (node)
            {
            case ShellUriHandler.GlobalRouteItem globalRoute:
                if (globalRoute.IsFinished)
                {
                    _globalRouteMatches.Add(globalRoute.SourceRoute);
                }
                break;

            case Shell shell:
                if (shell == Shell)
                {
                    return;
                }

                Shell = shell;
                break;

            case ShellItem item:
                if (Item == item)
                {
                    return;
                }

                Item = item;
                break;

            case ShellSection section:
                if (Section == section)
                {
                    return;
                }

                Section = section;

                if (Item == null)
                {
                    Item = Section.Parent as ShellItem;
                    _fullSegments.Add(Item.Route);
                }

                break;

            case ShellContent content:
                if (Content == content)
                {
                    return;
                }

                Content = content;
                if (Section == null)
                {
                    Section = Content.Parent as ShellSection;
                    _fullSegments.Add(Section.Route);
                }

                if (Item == null)
                {
                    Item = Section.Parent as ShellItem;
                    _fullSegments.Insert(0, Item.Route);
                }

                break;
            }

            if (Item?.Parent is Shell s)
            {
                Shell = s;
            }

            // if shellSegment == userSegment it means the implicit route is part of the request
            if (Routing.IsUserDefined(shellSegment) || shellSegment == userSegment || shellSegment == NextSegment)
            {
                _matchedSegments.Add(shellSegment);
            }

            _fullSegments.Add(shellSegment);
        }
Exemple #7
0
        public async Task GoToAsync(ShellNavigationParameters shellNavigationParameters)
        {
            if (shellNavigationParameters.PagePushing != null)
            {
                Routing.RegisterImplicitPageRoute(shellNavigationParameters.PagePushing);
            }

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

            var  navigationRequest = ShellUriHandler.GetNavigationRequest(_shell, state.FullLocation, enableRelativeShellRoutes, shellNavigationParameters: shellNavigationParameters);
            bool isRelativePopping = ShellUriHandler.IsTargetRelativePop(shellNavigationParameters);

            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);

            ApplyQueryAttributes(_shell, queryData, 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;

            // 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 == NavigationRequest.WhatToDoWithTheStack.ReplaceIt)
            {
                modalStackPreBuilt = true;

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

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

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

                if (shellSection != null)
                {
                    ApplyQueryAttributes(shellSection, queryData, 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;
                }

                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 != NavigationRequest.WhatToDoWithTheStack.ReplaceIt)
                {
                    // TODO get rid of this hack and fix so if there's a stack the current page doesn't display
                    await Device.InvokeOnMainThreadAsync(() =>
                    {
                        return(_shell.CurrentItem.CurrentItem.GoToAsync(navigationRequest, queryData, animate, isRelativePopping));
                    });
                }
                else if (navigationRequest.Request.GlobalRoutes.Count == 0 &&
                         navigationRequest.StackRequest == NavigationRequest.WhatToDoWithTheStack.ReplaceIt &&
                         currentShellSection?.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 Device.InvokeOnMainThreadAsync(() =>
                    {
                        return(_shell.CurrentItem.CurrentItem.GoToAsync(navigationRequest, queryData, animate, isRelativePopping));
                    });
                }
            }
            else
            {
                await _shell.CurrentItem.CurrentItem.GoToAsync(navigationRequest, queryData, animate, isRelativePopping);
            }

            _accumulateNavigatedEvents = false;

            // this can be null in the event that no navigation actually took place!
            if (_accumulatedEvent != null)
            {
                HandleNavigated(_accumulatedEvent);
            }
        }
Exemple #8
0
        public static void ApplyQueryAttributes(Element element, IDictionary <string, string> query, bool isLastItem, bool isPopping)
        {
            string prefix = "";

            if (!isLastItem)
            {
                var route = Routing.GetRoute(element);
                if (string.IsNullOrEmpty(route) || Routing.IsImplicit(route))
                {
                    return;
                }
                prefix = route + ".";
            }

            //if the lastItem is implicitly wrapped, get the actual ShellContent
            if (isLastItem)
            {
                if (element is IShellItemController shellitem && shellitem.GetItems().FirstOrDefault() is ShellSection section)
                {
                    element = section;
                }
                if (element is IShellSectionController shellsection && shellsection.GetItems().FirstOrDefault() is ShellContent content)
                {
                    element = content;
                }
                if (element is ShellContent shellcontent && shellcontent.Content is Element e)
                {
                    element = e;
                }
            }

            if (!(element is BaseShellItem baseShellItem))
            {
                baseShellItem = element?.Parent as BaseShellItem;
            }

            //filter the query to only apply the keys with matching prefix
            var filteredQuery = new Dictionary <string, string>(query.Count);

            foreach (var q in query)
            {
                if (!q.Key.StartsWith(prefix, StringComparison.Ordinal))
                {
                    continue;
                }
                var key = q.Key.Substring(prefix.Length);
                if (key.Contains("."))
                {
                    continue;
                }
                filteredQuery.Add(key, q.Value);
            }


            if (baseShellItem is ShellContent)
            {
                baseShellItem.ApplyQueryAttributes(MergeData(element, filteredQuery, isPopping));
            }
            else if (isLastItem)
            {
                element.SetValue(ShellContent.QueryAttributesProperty, MergeData(element, query, isPopping));
            }

            IDictionary <string, string> MergeData(Element shellElement, IDictionary <string, string> data, bool isPopping)
            {
                if (!isPopping)
                {
                    return(data);
                }

                var returnValue = new Dictionary <string, string>(data);

                var existing = (IDictionary <string, string>)shellElement.GetValue(ShellContent.QueryAttributesProperty);

                if (existing == null)
                {
                    return(data);
                }

                foreach (var datum in existing)
                {
                    if (!returnValue.ContainsKey(datum.Key))
                    {
                        returnValue[datum.Key] = datum.Value;
                    }
                }

                return(returnValue);
            }
        }