Example #1
0
        internal static NavigationRequest GetNavigationRequest(Shell shell, Uri uri, bool enableRelativeShellRoutes = false, bool throwNavigationErrorAsException = true, ShellNavigationParameters shellNavigationParameters = null)
        {
            uri = FormatUri(uri, shell);

            // figure out the intent of the Uri
            NavigationRequest.WhatToDoWithTheStack whatDoIDo = CalculateStackRequest(uri);

            Uri request = ConvertToStandardFormat(shell, uri);


            var possibleRouteMatches = GenerateRoutePaths(shell, request, uri, enableRelativeShellRoutes);

            if (possibleRouteMatches.Count == 0)
            {
                if (throwNavigationErrorAsException)
                {
                    throw new ArgumentException($"unable to figure out route for: {uri}", nameof(uri));
                }

                return(null);
            }
            else if (possibleRouteMatches.Count > 1)
            {
                string[] matches = new string[possibleRouteMatches.Count];
                int      i       = 0;
                foreach (var match in possibleRouteMatches)
                {
                    matches[i] = match.PathFull;
                    i++;
                }

                string matchesFound = String.Join(",", matches);

                if (throwNavigationErrorAsException)
                {
                    throw new ArgumentException($"Ambiguous routes matched for: {uri} matches found: {matchesFound}", nameof(uri));
                }

                return(null);
            }

            var theWinningRoute = possibleRouteMatches[0];

            RequestDefinition definition =
                new RequestDefinition(theWinningRoute, shell);

            NavigationRequest navigationRequest = new NavigationRequest(definition, whatDoIDo, request.Query, request.Fragment);

            return(navigationRequest);
        }
Example #2
0
        // This is used for navigation events that don't effect the currently visible page
        // InsertPageBefore/RemovePage
        async void SendHandlerUpdate(bool animated)
        {
            try
            {
                Interlocked.Increment(ref _waitingCount);
                await SemaphoreSlim.WaitAsync();

                var trulyReadOnlyNavigationStack = new List <IView>(NavigationStack);
                var request = new NavigationRequest(trulyReadOnlyNavigationStack, animated);
                ((IStackNavigation)this).RequestNavigation(request);
            }
            finally
            {
                Interlocked.Decrement(ref _waitingCount);
                SemaphoreSlim.Release();
            }
        }
        async Task SendHandlerUpdateAsync(bool animated, bool push = false, bool pop = false, bool popToRoot = false)
        {
            // Wait for any pending navigation tasks to finish
            await WaitForCurrentNavigationTask();

            var completionSource = new TaskCompletionSource <object>();

            CurrentNavigationTask = completionSource.Task;
            _taskCompletionSource = completionSource;

            // We create a new list to send to the handler because the structure backing
            // The Navigation stack isn't immutable
            var previousPage             = CurrentPage;
            var immutableNavigationStack = new List <IView>(NavigationStack);

            // Alert currently visible pages that navigation is happening
            SendNavigating();

            // Create the request for the handler
            var request = new NavigationRequest(immutableNavigationStack, animated);

            ((INavigationView)this).RequestNavigation(request);

            // Wait for the handler to finish processing the navigation
            await completionSource.Task;

            // Send navigated event to currently visible pages and associated navigation event
            SendNavigated(previousPage);
            if (push)
            {
                Pushed?.Invoke(this, new NavigationEventArgs(CurrentPage));
            }
            else if (pop)
            {
                Popped?.Invoke(this, new NavigationEventArgs(previousPage));
            }
            else
            {
                PoppedToRoot?.Invoke(this, new NavigationEventArgs(previousPage));
            }
        }
Example #4
0
 void IStackNavigation.RequestNavigation(NavigationRequest eventArgs)
 {
     Handler?.Invoke(nameof(IStackNavigation.RequestNavigation), eventArgs);
 }
Example #5
0
        async Task SendHandlerUpdateAsync(
            bool animated,
            Action processStackChanges,
            Action firePostNavigatingEvents,
            Action fireNavigatedEvents)
        {
            if (!_setForMaui || this.IsShimmed())
            {
                return;
            }

            processStackChanges?.Invoke();

            if (Handler == null)
            {
                return;
            }

            try
            {
                Interlocked.Increment(ref _waitingCount);

                // Wait for pending navigation tasks to finish
                await SemaphoreSlim.WaitAsync();

                var currentNavRequestTaskSource = new TaskCompletionSource <object>();
                _allPendingNavigationCompletionSource ??= new TaskCompletionSource <object>();

                if (CurrentNavigationTask == null)
                {
                    CurrentNavigationTask = _allPendingNavigationCompletionSource.Task;
                }
                else if (CurrentNavigationTask != _allPendingNavigationCompletionSource.Task)
                {
                    throw new InvalidOperationException("Pending Navigations still processing");
                }

                _currentNavigationCompletionSource = currentNavRequestTaskSource;

                // We create a new list to send to the handler because the structure backing
                // The Navigation stack isn't immutable
                var immutableNavigationStack = new List <IView>(NavigationStack);
                firePostNavigatingEvents?.Invoke();

                // Create the request for the handler
                var request = new NavigationRequest(immutableNavigationStack, animated);
                ((IStackNavigation)this).RequestNavigation(request);

                // Wait for the handler to finish processing the navigation
                // This task completes once the handler calls INavigationView.Finished
                await currentNavRequestTaskSource.Task;
            }
            finally
            {
                if (Interlocked.Decrement(ref _waitingCount) == 0)
                {
                    _allPendingNavigationCompletionSource.SetResult(new object());
                    _allPendingNavigationCompletionSource = null;
                }

                SemaphoreSlim.Release();
            }

            // Send navigated event to currently visible pages and associated navigation event
            fireNavigatedEvents?.Invoke();
        }
 void INavigationView.RequestNavigation(NavigationRequest eventArgs)
 {
     Handler?.Invoke(nameof(INavigationView.RequestNavigation), eventArgs);
 }
            void SendHandlerUpdate(bool animated)
            {
                var request = new NavigationRequest(GetNavigationStack(), false);

                Owner.Handler?.Invoke(nameof(INavigationView.RequestNavigation), request);
            }
Example #8
0
        public static ShellNavigationSource CalculateNavigationSource(Shell shell, ShellNavigationState current, NavigationRequest request)
        {
            if (request.StackRequest == NavigationRequest.WhatToDoWithTheStack.PushToIt)
            {
                return(ShellNavigationSource.Push);
            }

            if (current == null)
            {
                return(ShellNavigationSource.ShellItemChanged);
            }

            var targetUri  = ShellUriHandler.ConvertToStandardFormat(shell, request.Request.FullUri);
            var currentUri = ShellUriHandler.ConvertToStandardFormat(shell, current.FullLocation);

            var targetPaths  = ShellUriHandler.RetrievePaths(targetUri.PathAndQuery);
            var currentPaths = ShellUriHandler.RetrievePaths(currentUri.PathAndQuery);

            var targetPathsLength  = targetPaths.Length;
            var currentPathsLength = currentPaths.Length;

            if (targetPathsLength < 4 || currentPathsLength < 4)
            {
                return(ShellNavigationSource.Unknown);
            }

            if (targetPaths[1] != currentPaths[1])
            {
                return(ShellNavigationSource.ShellItemChanged);
            }
            if (targetPaths[2] != currentPaths[2])
            {
                return(ShellNavigationSource.ShellSectionChanged);
            }
            if (targetPaths[3] != currentPaths[3])
            {
                return(ShellNavigationSource.ShellContentChanged);
            }

            if (targetPathsLength == currentPathsLength)
            {
                return(ShellNavigationSource.Unknown);
            }

            if (targetPathsLength < currentPathsLength)
            {
                for (var i = 0; i < targetPathsLength; i++)
                {
                    var targetPath = targetPaths[i];
                    if (targetPath != currentPaths[i])
                    {
                        break;
                    }

                    if (i == targetPathsLength - 1)
                    {
                        if (targetPathsLength == 4)
                        {
                            return(ShellNavigationSource.PopToRoot);
                        }

                        return(ShellNavigationSource.Pop);
                    }
                }

                if (targetPaths[targetPathsLength - 1] == currentPaths[currentPathsLength - 1])
                {
                    return(ShellNavigationSource.Remove);
                }

                if (targetPathsLength == 4)
                {
                    return(ShellNavigationSource.PopToRoot);
                }

                return(ShellNavigationSource.Pop);
            }
            else if (targetPathsLength > currentPathsLength)
            {
                for (var i = 0; i < currentPathsLength; i++)
                {
                    if (targetPaths[i] != currentPaths[i])
                    {
                        break;
                    }

                    if (i == targetPathsLength - 1)
                    {
                        return(ShellNavigationSource.Push);
                    }
                }
            }

            if (targetPaths[targetPathsLength - 1] == currentPaths[currentPathsLength - 1])
            {
                return(ShellNavigationSource.Insert);
            }

            return(ShellNavigationSource.Push);
        }
Example #9
0
 void IStackNavigation.RequestNavigation(NavigationRequest eventArgs)
 {
     _handlerBasedNavigationCompletionSource = new TaskCompletionSource <object>();
     Handler.Invoke(nameof(IStackNavigation.RequestNavigation), eventArgs);
 }