MPowerKit.Navigation.Popups 1.1.7

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package MPowerKit.Navigation.Popups --version 1.1.7                
NuGet\Install-Package MPowerKit.Navigation.Popups -Version 1.1.7                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MPowerKit.Navigation.Popups" Version="1.1.7" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add MPowerKit.Navigation.Popups --version 1.1.7                
#r "nuget: MPowerKit.Navigation.Popups, 1.1.7"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install MPowerKit.Navigation.Popups as a Cake Addin
#addin nuget:?package=MPowerKit.Navigation.Popups&version=1.1.7

// Install MPowerKit.Navigation.Popups as a Cake Tool
#tool nuget:?package=MPowerKit.Navigation.Popups&version=1.1.7                

MPowerKit .NET MAUI MVVM navigation framework.

Supports regular/modal navigation, opening/closing windows, multiple windows, regions, popups

Inspired by Prism navigation framework

Since Prism for .NET MAUI has some critical (for our company) bugs and different behavior comparing to Prism.Forms, we decided to write our own navigation framework. This library brings you the same principle for navigation througn the MAUI app as Prism, but has absolutely different implementation and a bit improved performance. It also brings (in our opinion) proper way to handle 'System back button' click, works nad has same behavior for all platforms.

Available Nugets

Framework Nuget
MPowerKit.Navigation.Core Nuget
MPowerKit.Navigation Nuget
MPowerKit.Navigation.Popups Nuget
MPowerKit.Navigation.Regions Nuget

MPowerKit.Navigation.Core

This is the core library for MPowerKit.Navigation and other libraries. It contains core functionality, utility classes and interfaces.

Awares

Same as in Prism, aware interfaces are here to know when and what page event happens.

IInitializeAware

It has only one interface method void Initialize(INavigationParameters parameters);. This method is executed right after the page and it's viewmodel has been created and not attached to visual tree. Executes for each page in navigation stack continuously in direct order. Accepts INavigationParameters as input arguments. Executed only once during the lifetime of the page. If you want your page or it's viewmodel know about this event, it must implement this interface.

It's purpose to get INavigationParameters and may be subscribe to some events.

Note: There is no IInitializeAsyncAware interface, because in mobile development it is not a good practise calling async methods when your page is not atatched to visual tree

IDestructible

It has only one interface method void Desctroy();. This method is executed right after the page and it's viewmodel has been detached from visual tree and needs to be GCed. Executes for each page in navigation stack continuously in reverse order. Executed only once during the lifetime of the page. If you want your page or it's viewmodel know about this event, it must implement this interface.

It's purpose to unsubscribe from events and clear resources.

MPowerKit.Navigation

WIP

MPowerKit.Navigation.Popups

This library based on MPowerKit.Navigation and MPowerKit.Popups libraries

Setup

Add UsePopupNavigation() to MPowerKitBuilder in your MauiProgram.cs file as next

builder
    .UseMauiApp<App>()
    .UseMPowerKitNavigation(mpowerBuilder =>
    {
        mpowerBuilder.ConfigureServices(s =>
        {
            s.RegisterForNavigation<MainPage>();
            s.RegisterForNavigation<TestPopupPage>();
        })
        .UsePopupNavigation()
        .OnAppStart("NavigationPage/MainPage");
    });

When you specify .UsePopupNavigation() it registers MPowerKitPopupsWindow as main class for every window, it is responsible for system back button. It inherits MPowerKitWindow which is main class for window in MPowerKit.Navigation, it also responsible for system back button on every platform, even in mac and ios (top-left back button on the page's toolbar)

Register your popup pages
mpowerBuilder.ConfigureServices(s =>
{
    s.RegisterForNavigation<TestPopupPage>();
})
  • The popup will be resolved by it's nameof()
  • No view model is specified, which means it has BindingContext set to new object();

or

mpowerBuilder.ConfigureServices(s =>
{
    s.RegisterForNavigation<TestPopupPage, TestPopupViewModel>();
})
  • The popup will be resolved by it's nameof()
  • The view model is TestPopupViewModel

or

mpowerBuilder.ConfigureServices(s =>
{
    s.RegisterForNavigation<TestPopupPage, TestPopupViewModel>("TheAssociationNameForYourPopup");
})
  • The popup will be resolved by association name, which is preferred way
  • The view model is TestPopupViewModel

Usage

Each popup page must inherit from PopupPage of MPowerKit.Popups library

IPopupDialogAware

To have full control over the popup flow it is better that your popup or popup's viewmodel implement this interface. This interface gives you an ability to close popup programmatically from popup or it's viewmodel. IPopupDialogAware interface provides only one property RequestClose. It is an Action. You should call it when you want to close the popup. It accepts a tuple with Confirmation object and a boolean whether animated or not. The value for RequestClose property is set under the hood by the framework, so you don't need to do smth extra with it.

Confirmation is a record which accepts 2 parameters:

  1. Boolean whether confirmed or not;
  2. INavigationParameters to pass the parameters back from popup to popup caller (it is optional).
Example
public class TestPopupViewModel : IPopupDialogAware
{
    public Action<(Confirmation Confirmation, bool Animated)> RequestClose { get; set; }

    protected virtual async Task Cancel(object obj = null)
    {
        var nparams = new NavigationParameters
        {
            { NavigationConstants.CloseParameter, obj }
        };

        RequestClose?.Invoke((new Confirmation(false, nparams), true));
    }

    protected virtual async Task Confirm(object obj = null)
    {
        var nparams = new NavigationParameters
        {
            { NavigationConstants.CloseParameter, obj }
        };

        RequestClose?.Invoke((new Confirmation(true, nparams), true));
    }
}
IPopupNavigationService

Main unit of work of this library is IPopupNavigationService. Under the hood it is registered as scoped service (NOT SINGLETONE), which means that it knows from which page it was opened to know the parent window it is attached to. So, in theory you can open different popups in different windows in same time.

Inject IPopupNavigationService to your page's or viewmodel's contructor.

IPopupNavigationService describes 4 methods:

  1. Show 'fire-and-forget' popup:
ValueTask<NavigationResult> ShowPopupAsync(string popupName, INavigationParameters? parameters = null, bool animated = true, Action<Confirmation>? closeAction = null);

When you invoke this method it will show the popup and the main thread will continue doing it's very important work. You can provide close callback which accepts Confirmation object with boolean whether confirmed or not and INavigationParameters parameters. it invokes all necessary aware interfaces you specified for your popup or it's viewmodel. The result of showing popup is NavigationResult

  1. Show awaitable popup:
ValueTask<PopupResult> ShowAwaitablePopupAsync(string popupName, INavigationParameters? parameters = null, bool animated = true);

When you invoke this method it will show the popup and it will await until the popup is closed. The reslut of this method is PopupResult. PopupResult is inherited from NavigationResult. It has extra property for Confirmation object to know how the popup was closed.

  1. Hide the last popup from popup stack:
ValueTask<NavigationResult> HidePopupAsync(bool animated = true);

Hides the last popup available in the popup stack. The stack is controlled by the MPowerKit.Popups framework.

  1. Hide specific popup:
ValueTask<NavigationResult> HidePopupAsync(PopupPage page, bool animated = true);

Hides the specified popup if it was opened. The difference with MPowerKit.Popups that it invokes all necessary aware interfaces you specified for your popup or it's viewmodel.

MPowerKit.Navigation.Regions

Like MPowerKit.Navigation Regions library is very similar to Prism's one. It has same sense, but different implementation.

Shortly what it is: In MAUI you can navigate only through pages, but what if you need to have big page with few different sections, let's call them, regions. For example: TabView or some desktop screen with sections. Do we need to keep all logic in one god viewmodel? - With regions no. It gives you simple and flexible way to navigate to the regions (sections on UI) from your page or viewmodel, or even from another region. Each region can hold as much views as you like, but only one will be visible at the moment. And you can simply put all logic related to the section inside the region viewmodel. Regions can be recursive.

Setup

Add UseMPowerKitRegions() to your MauiProgram.cs file as next

builder
    .UseMauiApp<App>()
    .UseMPowerKitRegions();

Regions can work with(out) MPowerKit.Navigation or MPowerKit.Navigation.Popups.

builder
    .UseMauiApp<App>()
    .UseMPowerKitNavigation(mpowerBuilder =>
    {
        mpowerBuilder.ConfigureServices(s =>
        {
            s.RegisterForNavigation<MainPage>();
            s.RegisterForNavigation<RegionView1>();
        })
        .OnAppStart("NavigationPage/MainPage");
    })
    .UseMPowerKitRegions();

Note: if you are using regions in couple with MPowerKit.Navigation you can specify whether you want your region views get parent page's events like navigation, destroy, lifecycle etc. Just add UsePageEventsInRegions() to mpowerBuilder

builder
    .UseMauiApp<App>()
    .UseMPowerKitNavigation(mpowerBuilder =>
    {
        mpowerBuilder.ConfigureServices(s =>
        {
            s.RegisterForNavigation<MainPage>();
            s.RegisterForNavigation<RegionView1>();
        })
        .UsePageEventsInRegions()
        .OnAppStart("NavigationPage/MainPage");
    })
    .UseMPowerKitRegions();
Register your region views
builder.Services
    .RegisterForNavigation<RegionView1>();
  • The region view will be resolved by it's nameof()
  • No view model is specified, which means it has BindingContext set to new object();

or

builder.Services
    .RegisterForNavigation<RegionView1, Region1ViewModel>();
  • The region view will be resolved by it's nameof()
  • The view model is Region1ViewModel

or

builder.Services
    .RegisterForNavigation<RegionView1, Region1ViewModel>("RegionViewAssociationName");
  • The region view will be resolved by association name, which is preferred way
  • The view model is Region1ViewModel

Usage

Each region should have the parent container which will be the so-called region holder. This region holder has to be typeof(ContentView).

In your xaml:

Firstly add namespace

xmlns:regions="clr-namespace:MPowerKit.Regions;assembly=MPowerKit.Regions"

and then just simple to use

<ContentView regions:RegionManager.RegionName="YourVeryMeaningfulRegionName" />

or, unlike Prism, it can have dynamic name, for example if you need to bind it to some ID.

<ContentView regions:RegionManager.RegionName="{Binding DynamicString}" />

This is very helpful if you use it, for example, with TabView and you need to open new tab with tab specific dynamic data which has region(s). With static names you are not able to do such trick.

!!! Important: the region names MUST be unique throughout the entire app or it will crash!!!

To remove region holder from region registrations there is hidden method RegionManager.RemoveHolder(string? key).

Note: you should not use it, if you use MPowerKit.Regions in couple with MPowerKit.Navigation

IRegionManager

Inject IRegionManager to your view's or viewmodel's contructor.

This interface is registered as a singleton and describes 2 methods:

  1. New navigation to the region:
NavigationResult NavigateTo(string regionName, string viewName, INavigationParameters? parameters = null);

Performs navigation within an empty region holder. It creates an IRegion object that describes the region with a region stack and then pushes the chosen view into the region. If the region holder already contains child views, it will clear the region stack and push the new view into the region.

  1. Get all child regions for chosen view:
IEnumerable<IRegion> GetRegions(VisualElement? regionHolder);

Retrieves all child regions associated with a chosen region holder. It can be particularly useful when you need to clean up resources and invoke lifecycle events for these regions.

Example
IRegionManager _regionManager;

_regionManger.NavigateTo("YourRegionName", "RegionViewAssociationName", optionalNavigationParametersObject);
IRegion

To use IRegion object just inject it to your region view ot it's viewmodel and then you will have the control over your region stack.

This interface is registered as scoped service. It means that each region holder contains it's own IRegion object which can be injected into each region view it holds. This object is responsible for navigation inside the region it describes.

Each region has it's region stack and CurrentView. Region stack is just Grid with children. So it means that all of region views are currently attached to the visual tree but only one is visible. Visible region view is CurrentView.

This interface describes 7 main methods:

  1. Replace all
NavigationResult ReplaceAll(string viewName, INavigationParameters? parameters);```

Replaces entire region stack, calls all implemented aware interfaces and pushes new region view to the region holder.

  1. Push new view
NavigationResult Push(string viewName, INavigationParameters? parameters);

Detects index of CurrentView in the stack, clears all view after CurrentView and pushes new view after CurrentView and makes it to be CurrentView

  1. Push new view backwards
NavigationResult PushBackwards(string viewName, INavigationParameters? parameters);

Same as Push but clears all views before CurrentView in the stack and pushes new view before CurrentView and makes it to be CurrentView.

  1. Go back through the stack
NavigationResult GoBack(INavigationParameters? parameters);

Checks whether it can navigate back through the region stack and does backwards navigation invoking INavigationAware interface.

  1. Go forward through the stack
NavigationResult GoForward(INavigationParameters? parameters);

Same as GoBack but to the opposite direction.

  1. Can go back
bool CanGoBack();

Checks whether it can navigate back through the region stack.

  1. Can go forward
bool CanGoForward();

Same as CanGoBack but to the opposite direction.

Also, this interface describes another few utility methods which invoke aware interfaces.

Region views or their viewmodels can implement next aware interfaces: IInitializeAware, INavigationAware, IDestructible, IWindowLifecycleAware, IPageLifecycleAware

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-android34.0 is compatible.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-ios17.2 is compatible.  net8.0-maccatalyst was computed.  net8.0-maccatalyst17.2 is compatible.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net8.0-windows10.0.22621 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.3.0.1 49 11/5/2024
1.3.0 149 10/18/2024
1.2.1.4 137 9/9/2024
1.2.1.3 106 8/30/2024
1.2.1.2 91 8/28/2024
1.2.1.1 89 8/28/2024
1.2.1 176 8/16/2024
1.2.0 120 8/15/2024
1.1.10 114 8/6/2024
1.1.9.1 68 7/30/2024
1.1.9 66 7/30/2024
1.1.8.1 128 4/22/2024
1.1.8 109 4/19/2024
1.1.7.2 137 2/15/2024
1.1.7.1 104 2/15/2024
1.1.7 123 1/30/2024
1.1.5 148 1/2/2024
1.1.4 128 12/24/2023
1.1.2 122 12/20/2023
1.1.1 136 12/18/2023
1.0.1 137 12/15/2023