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); }
// 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)); } }
void IStackNavigation.RequestNavigation(NavigationRequest eventArgs) { Handler?.Invoke(nameof(IStackNavigation.RequestNavigation), eventArgs); }
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); }
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); }
void IStackNavigation.RequestNavigation(NavigationRequest eventArgs) { _handlerBasedNavigationCompletionSource = new TaskCompletionSource <object>(); Handler.Invoke(nameof(IStackNavigation.RequestNavigation), eventArgs); }