Skip to content
This repository has been archived by the owner on Feb 16, 2023. It is now read-only.

Global Navigation Observer #37

Merged
merged 11 commits into from
May 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
<PrismLicenseFile>$(MSBuildThisFileDirectory)LICENSE</PrismLicenseFile>
<PackageTags>prism;maui;dotnet-maui;xaml;mvvm;ios;android;mac;winui</PackageTags>
<Copyright>Copyright Dan Siegel 2021</Copyright>
<Description>This is a special preview package. In order to use this be sure that you have installed the Maui workload with Visual Studio 2022 preview 4 or later. Alternatively you may use Maui-Check to ensure that your environment has the required prerequesites to build from the command line with Visual Studio Code.
<Description>
Prism is a fully open source version of the Prism guidance originally produced by Microsoft Patterns &amp; Practices. Prism provides an implementation of a collection of design patterns that are helpful in writing well structured, maintainable, and testable XAML applications, including MVVM, dependency injection, commanding, event aggregation, and more. Prism's core functionality is a shared library targeting the .NET Framework and .NET Standard. Features that need to be platform specific are implemented in the respective libraries for the target platform (WPF, Uno Platform, Xamarin Forms, and .NET MAUI).

As this is special preview build there are no docs, be sure to check out the source repo at: https://github.com/dansiegel/prism.maui </Description>
Prism for .NET MAUI helps you more easily design and build rich, flexible, and easy to maintain .NET MAUI applications. This library provides user interface composition as well as modularity support.
</Description>
<!-- HACK: WinUI seems to have issues without this -->
<GenerateLibraryLayout>true</GenerateLibraryLayout>
<DisableEmbeddedXbf>false</DisableEmbeddedXbf>
Expand All @@ -38,7 +40,7 @@ As this is special preview build there are no docs, be sure to check out the sou

<ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning"
Version="3.5.104"
Version="3.5.107"
PrivateAssets="all" />
<PackageReference Include="Microsoft.SourceLink.GitHub"
Version="1.1.1"
Expand Down
21 changes: 20 additions & 1 deletion Prism.Maui.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6CAB3327-8C0
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Prism.DryIoc.Maui", "src\Prism.DryIoc.Maui\Prism.DryIoc.Maui.csproj", "{6C5C1F1F-DA92-4307-862F-5034BF8B0858}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Prism.Maui", "src\Prism.Maui\Prism.Maui.csproj", "{6171FE41-1F11-4CFA-8FD8-8222B97C7C63}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Prism.Maui", "src\Prism.Maui\Prism.Maui.csproj", "{6171FE41-1F11-4CFA-8FD8-8222B97C7C63}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Prism.DryIoc.Shared", "src\Prism.DryIoc.Shared\Prism.DryIoc.Shared.shproj", "{6E7EC81D-DA39-4C4F-A898-0148558C34F4}"
EndProject
Expand All @@ -30,6 +30,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiModule", "sample\MauiModule\MauiModule.csproj", "{EB8CD219-0CA7-4AE3-A7B7-6D883400CCE0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Prism.Maui.Rx", "src\Prism.Maui.Rx\Prism.Maui.Rx.csproj", "{D364B3F0-2D41-4EF8-BE1D-D83825322F61}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Prism.DryIoc.Shared\Prism.DryIoc.Shared.projitems*{6c5c1f1f-da92-4307-862f-5034bf8b0858}*SharedItemsImports = 5
Expand Down Expand Up @@ -127,6 +129,22 @@ Global
{EB8CD219-0CA7-4AE3-A7B7-6D883400CCE0}.Release|x64.Build.0 = Release|Any CPU
{EB8CD219-0CA7-4AE3-A7B7-6D883400CCE0}.Release|x86.ActiveCfg = Release|Any CPU
{EB8CD219-0CA7-4AE3-A7B7-6D883400CCE0}.Release|x86.Build.0 = Release|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Debug|arm64.ActiveCfg = Debug|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Debug|arm64.Build.0 = Debug|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Debug|x64.ActiveCfg = Debug|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Debug|x64.Build.0 = Debug|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Debug|x86.ActiveCfg = Debug|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Debug|x86.Build.0 = Debug|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Release|Any CPU.Build.0 = Release|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Release|arm64.ActiveCfg = Release|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Release|arm64.Build.0 = Release|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Release|x64.ActiveCfg = Release|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Release|x64.Build.0 = Release|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Release|x86.ActiveCfg = Release|Any CPU
{D364B3F0-2D41-4EF8-BE1D-D83825322F61}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -138,6 +156,7 @@ Global
{3BFAB205-050B-47B7-9AB8-BE799E07DA90} = {7CB47440-CCBC-4E16-B2B9-9FD472154117}
{16AEEF3D-B119-4EE0-9B1F-B9E0FDF0EEAB} = {06F06128-578F-449D-B3D6-D04A531B1018}
{EB8CD219-0CA7-4AE3-A7B7-6D883400CCE0} = {06F06128-578F-449D-B3D6-D04A531B1018}
{D364B3F0-2D41-4EF8-BE1D-D83825322F61} = {6CAB3327-8C0A-4D0B-BF18-CEFD15B84BA7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7E696A15-8B47-4BC2-8997-071E61157406}
Expand Down
11 changes: 11 additions & 0 deletions sample/PrismMauiDemo/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,21 @@ public static MauiApp CreateMauiApp()
})
.RegisterTypes(containerRegistry =>
{
containerRegistry.RegisterGlobalNavigationObserver();
containerRegistry.RegisterForNavigation<MainPage>();
containerRegistry.RegisterForNavigation<RootPage>();
containerRegistry.RegisterForNavigation<SamplePage>();
})
.AddGlobalNavigationObserver(context => context.Subscribe(x =>
{
if (x.Type == NavigationRequestType.Navigate)
Console.WriteLine($"Navigation: {x.Type} - {x.Uri}");
else
Console.WriteLine($"Navigation: {x.Type}");

var status = x.Cancelled ? "Cancelled" : x.Result.Success ? "Success" : "Failed";
Console.WriteLine($"Result: {status}");
}))
.OnAppStart(navigationService => navigationService.CreateBuilder()
.AddNavigationSegment("MainPage")
.AddNavigationPage()
Expand Down
1 change: 1 addition & 0 deletions sample/PrismMauiDemo/PrismMauiDemo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@

<ItemGroup>
<ProjectReference Include="..\..\src\Prism.DryIoc.Maui\Prism.DryIoc.Maui.csproj" />
<ProjectReference Include="..\..\src\Prism.Maui.Rx\Prism.Maui.Rx.csproj" />
<ProjectReference Include="..\..\src\Prism.Maui\Prism.Maui.csproj" />
<ProjectReference Include="..\MauiModule\MauiModule.csproj" />
</ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Prism.DryIoc.Maui/Prism.DryIoc.Maui.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<UseMaui>true</UseMaui>
<ImplicitUsings>true</ImplicitUsings>
<Description>Prism.DryIoc.Maui provides the implementation of Prism's IContainerExtension using the DryIoc container. This is currently the only supported container for .NET MAUI.</Description>
</PropertyGroup>

<ItemGroup>
Expand Down
29 changes: 29 additions & 0 deletions src/Prism.Maui.Rx/GlobalNavigationObserver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.Reactive.Subjects;
using Prism.Events;

namespace Prism.Navigation;

internal class GlobalNavigationObserver : IGlobalNavigationObserver, IDisposable
{
private readonly Subject<NavigationRequestContext> _subject;
private SubscriptionToken _token;

public GlobalNavigationObserver(IEventAggregator eventAggregator)
{
_subject = new Subject<NavigationRequestContext>();
_token = eventAggregator.GetEvent<NavigationRequestEvent>().Subscribe(context => _subject.OnNext(context));
}

public IObservable<NavigationRequestContext> NavigationRequest => _subject;

public void Dispose()
{
if (_token is null)
return;

_token.Dispose();
_token = null;
_subject.Dispose();
}
}
8 changes: 8 additions & 0 deletions src/Prism.Maui.Rx/IGlobalNavigationObserver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System;

namespace Prism.Navigation;

public interface IGlobalNavigationObserver
{
IObservable<NavigationRequestContext> NavigationRequest { get; }
}
45 changes: 45 additions & 0 deletions src/Prism.Maui.Rx/NavigationObserverRegistrationExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Microsoft.Extensions.DependencyInjection;
using Prism.Ioc;

namespace Prism.Navigation;

public static class NavigationObserverRegistrationExtensions
{
private static bool s_IsRegistered;

public static IContainerRegistry RegisterGlobalNavigationObserver(this IContainerRegistry container)
{
if (s_IsRegistered)
return container;

s_IsRegistered = true;
return container.RegisterSingleton<IGlobalNavigationObserver, GlobalNavigationObserver>();
}

public static IServiceCollection RegisterGlobalNavigationObserver(this IServiceCollection services)
{
if (s_IsRegistered)
return services;

s_IsRegistered = true;
return services.AddSingleton<IGlobalNavigationObserver, GlobalNavigationObserver>();
}

public static PrismAppBuilder AddGlobalNavigationObserver(this PrismAppBuilder builder, Action<IObservable<NavigationRequestContext>> addObservable) =>
builder.OnInitialized(c =>
{
if (!s_IsRegistered)
throw new Exception("IGlobalNavigationObserver has not been registered. Be sure to call 'container.RegisterGlobalNavigationObserver()'.");

addObservable(c.Resolve<IGlobalNavigationObserver>().NavigationRequest);
});

public static PrismAppBuilder AddGlobalNavigationObserver(this PrismAppBuilder builder, Action<IContainerProvider, IObservable<NavigationRequestContext>> addObservable) =>
builder.OnInitialized(c =>
{
if (!s_IsRegistered)
throw new Exception("IGlobalNavigationObserver has not been registered. Be sure to call 'container.RegisterGlobalNavigationObserver()'.");

addObservable(c, c.Resolve<IGlobalNavigationObserver>().NavigationRequest);
});
}
17 changes: 17 additions & 0 deletions src/Prism.Maui.Rx/Prism.Maui.Rx.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>true</ImplicitUsings>
<Description>Prism.Maui.Rx is a support package for .NET MAUI developers. This package provides some helpers to access an IObservable for globally handling Navigation Request Results.</Description>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Prism.Maui\Prism.Maui.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Reactive" Version="5.0.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ private void NavigationPage_Popped(object sender, NavigationEventArgs e)
{
if (PageNavigationService.NavigationSource == PageNavigationSource.Device)
{
System.Diagnostics.Trace.WriteLine("NavigationPage has encountered an unhandled GoBack. Be sure to inherit from PrismNavigationPage.");
PageUtilities.HandleSystemGoBack(e.Page, AssociatedObject.CurrentPage);
}
}
Expand Down
15 changes: 2 additions & 13 deletions src/Prism.Maui/Common/PageUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,19 +229,8 @@ public static void SetCurrentPageDelegate(Func<Page, Page> getCurrentPageDelegat

public static async Task HandleNavigationPageGoBack(NavigationPage navigationPage)
{
var previousPage = navigationPage.CurrentPage;
var parameters = new NavigationParameters();
parameters.GetNavigationParametersInternal().Add(KnownInternalParameters.NavigationMode, NavigationMode.Back);
if (!CanNavigate(previousPage, parameters) ||
!await CanNavigateAsync(previousPage, parameters))
return;

PageNavigationService.NavigationSource = PageNavigationSource.NavigationService;
await navigationPage.PopAsync();
PageNavigationService.NavigationSource = PageNavigationSource.Device;
OnNavigatedFrom(previousPage, parameters);
OnNavigatedTo(navigationPage.CurrentPage, parameters);
DestroyPage(previousPage);
var navigationService = Navigation.Xaml.Navigation.GetNavigationService(navigationPage.CurrentPage);
await navigationService.GoBackAsync();
}

public static void HandleSystemGoBack(IView previousPage, IView currentPage)
Expand Down
8 changes: 8 additions & 0 deletions src/Prism.Maui/Events/NavigationRequestEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Prism.Navigation;

namespace Prism.Events;

public class NavigationRequestEvent : PubSubEvent<NavigationRequestContext>
{
}

5 changes: 5 additions & 0 deletions src/Prism.Maui/Navigation/KnownNavigationParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ public static class KnownNavigationParameters
/// </summary>
public const string UseModalNavigation = "useModalNavigation";

/// <summary>
/// Used to control whether the navigation should be animated.
/// </summary>
public const string Animated = "animated";

/// <summary>
/// Used to define a navigation parameter that is bound directly to a CommandParameter via <code>{Binding .}</code>.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions src/Prism.Maui/Navigation/NavigationRequestContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Prism.Navigation;

public record NavigationRequestContext
{
public bool Cancelled => Result?.Exception is not null && Result.Exception is NavigationException ne && ne.Message == NavigationException.IConfirmNavigationReturnedFalse;
public NavigationRequestType Type { get; init; }
public Uri? Uri { get; init; }
public INavigationParameters Parameters { get; init; }
public INavigationResult Result { get; init; }
}
8 changes: 8 additions & 0 deletions src/Prism.Maui/Navigation/NavigationRequestType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Prism.Navigation;

public enum NavigationRequestType
{
Navigate,
GoBack,
GoToRoot,
}
Loading