Instantly share code, notes, and snippets.
Created
December 1, 2021 10:19
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save Axemasta/0a08ca435d0c10a42efc34de2ce8f9f0 to your computer and use it in GitHub Desktop.
INavigationService Extensions for thread safe + error handled navigation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Threading.Tasks; | |
| using Prism; | |
| using Prism.Navigation; | |
| using Xamarin.Forms; | |
| using Xamarin.Essentials.Interfaces; | |
| using Xamarin.Essentials.Implementation; | |
| public static class NavigationServiceExtensions | |
| { | |
| public static IMainThread ImplementedInstance { get; } = new MainThreadImplementation(); | |
| public static async Task NavigateOnMainThread(this INavigationService navigationService, Func<Task<INavigationResult>> action, IMainThread mainThread) | |
| { | |
| INavigationResult result = null; | |
| if (mainThread is null) | |
| { | |
| mainThread = ImplementedInstance; | |
| } | |
| if (mainThread.IsMainThread) | |
| { | |
| result = await action.Invoke(); | |
| } | |
| else | |
| { | |
| result = await mainThread.InvokeOnMainThreadAsync(action); | |
| } | |
| navigationService.HandleNavigationResult(result); | |
| } | |
| public static async Task TryNavigateAsync(this INavigationService navigationService, Uri uri, | |
| INavigationParameters parameters = null, | |
| IMainThread mainThread = null) | |
| { | |
| Func<Task<INavigationResult>> navigation = () => navigationService.NavigateAsync(uri, parameters); | |
| await NavigateOnMainThread(navigationService, navigation, mainThread); | |
| } | |
| public static async Task TryNavigateModallyAsync(this INavigationService navigationService, Uri uri, | |
| INavigationParameters parameters = null, | |
| IMainThread mainThread = null) | |
| { | |
| Func<Task<INavigationResult>> navigation = () => navigationService.NavigateAsync(uri, parameters, true, true); | |
| await NavigateOnMainThread(navigationService, navigation, mainThread); | |
| } | |
| public static async Task TryNavigateAsync(this INavigationService navigationService, string path, | |
| INavigationParameters parameters = null, | |
| IMainThread mainThread = null) | |
| { | |
| Func<Task<INavigationResult>> navigation = () => navigationService.NavigateAsync(path, parameters); | |
| await NavigateOnMainThread(navigationService, navigation, mainThread); | |
| } | |
| public static async Task TryNavigateModallyAsync(this INavigationService navigationService, string path, | |
| INavigationParameters parameters = null, | |
| IMainThread mainThread = null) | |
| { | |
| Func<Task<INavigationResult>> navigation = () => navigationService.NavigateAsync(path, parameters, true, true); | |
| await NavigateOnMainThread(navigationService, navigation, mainThread); | |
| } | |
| public static async Task TryNavigateBackAsync(this INavigationService navigationService, | |
| INavigationParameters parameters = null, | |
| IMainThread mainThread = null) | |
| { | |
| Func<Task<INavigationResult>> navigation = () => navigationService.GoBackAsync(parameters); | |
| await NavigateOnMainThread(navigationService, navigation, mainThread); | |
| } | |
| public static async Task TryClearPopupStackAsync(this INavigationService navigationService, | |
| IMainThread mainThread = null) | |
| { | |
| Func<Task<INavigationResult>> navigation = () => navigationService.ClearPopupStackAsync(); | |
| await NavigateOnMainThread(navigationService, navigation, mainThread); | |
| } | |
| private static async void HandleNavigationResult(this INavigationService navigationService, | |
| INavigationResult navigationResult) | |
| { | |
| if (navigationResult is null) // This case should only occur in incorrectly setup unit tests | |
| return; | |
| if (!navigationResult.Success) | |
| { | |
| Exception ex = new InvalidNavigationException(); | |
| if (navigationResult.Exception != null) | |
| ex = navigationResult.Exception; | |
| var p = new NavigationParameters() | |
| { | |
| { ParameterConstants.ExceptionError, ex } | |
| }; | |
| var nav = await navigationService.NavigateAsync("NavigationErrorPage", p); | |
| if (!nav.Success) | |
| { | |
| SetMainPageFromException(ex); | |
| } | |
| } | |
| } | |
| private static void SetMainPageFromException(Exception ex) | |
| { | |
| var layout = new StackLayout | |
| { | |
| Padding = new Thickness(40) | |
| }; | |
| layout.Children.Add(new Label | |
| { | |
| Text = ex?.GetType()?.Name ?? "Unknown Error encountered", | |
| FontAttributes = FontAttributes.Bold, | |
| HorizontalOptions = LayoutOptions.Center | |
| }); | |
| layout.Children.Add(new ScrollView | |
| { | |
| Content = new Label | |
| { | |
| Text = $"{ex}", | |
| LineBreakMode = LineBreakMode.WordWrap | |
| } | |
| }); | |
| PrismApplicationBase.Current.MainPage = new ContentPage | |
| { | |
| Content = layout | |
| }; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment