EGoverde / Mvvm.Nucleus.Maui

MVVM Framework for MAUI mobile applications. Build on top of MAUI and the MVVM Community Toolkit.
https://www.nuget.org/packages/Mvvm.Nucleus.Maui
MIT License
4 stars 2 forks source link

Nucleus MVVM for MAUI

Nucleus MVVM is a framework written to be used in .NET MAUI projects. It is build on top of MAUI, the CommunityToolkit.Mvvm and the CommunityToolkit.Maui. Its purpose is for better separation of UI and logic using MVVM conventions.

NuGet version (Mvvm.Nucleus.Maui)

Highlighted features

Getting started

Nucleus MVVM is available as a NuGet package. After adding the package it requires little code to get started and remains similar to a regular MAUI app. It is recommended to add the Mvvm.Nucleus.Maui namespace to your GlobalUsings. To get started remove the default UseMauiApp<App> and configure Nucleus using the options:

            builder
            .UseNucleusMvvm<App, AppShell>(options =>
            {
                options.RegisterTypes(dependencyOptions => 
                    dependencyOptions.RegisterShellView<MyAbsoluteView, MyAbsoluteViewModel>("//MyAbsoluteView");
                    dependencyOptions.RegisterView<MyGlobalView, MyGlobalViewModel>("//MyGlobalView");
                );
            })
            .Etc..

Note that the CommunityToolkit.Maui is a dependency of Nucleus. You should not call UseMauiCommunityToolkit manually, as this is already done through UseNucleusMvvm.

See Navigation to see the usage and differences between RegisterShellView and RegisterView.

ViewModels can be of any type and support dependency injection. By implementing interfaces (see Event interfaces) they can trigger logic on events like navigation or its page appearing. It is recommended for a ViewModel to have ObserableObject as a base for its bindings.

An optional NucleusViewModel is included to have some boilerplate events like OnInitAsync() and OnRefreshAsync.

Configuration

Within the options the following additional settings can be changed:

See the Sample Project in the repository for more examples of Nucleus MVVM usage.

Services

Navigation

Navigation can be done through the INavigationService. Currently only the Shell implemention is supported. Navigation is done by either specifying the (type of the) View or a Route.

Views and their ViewModels need to be registered in MauiProgram.cs. Pages defined within AppShell.xaml are known as absolute routes and should be registered using RegisterShellView<MyView, MyViewModel>("//MyRoute"). It is important that the given route matches the XAML.

Any pages not defined witin AppShell.xaml are known as global routes and can be pushed from any page. You can register these simply as RegisterView<MyGlobalView, MyGlobalViewModel>(), as by default they will get their name as route. You can however supply a custom one. Routes always have to be unique, or the registration will fail.

Note that in Shell pages on the root-level (e.a. //home) will be reused after the intial navigation, even if set to Transient. See this issue

Passing data

When navigating an IDictionary<string, object> can be passed to the INavigationService, which will be passed to the Init and Refresh or various Navigated events. The dictionary will only be passed once and it will never be null. In routes query string parameters are supported as well (e.a. ?myValue=value), but not the recommended approach.

Values can be retrieved using regular IDictionary methods, but additionally there are the following extensions:

These parameters can also be used as described in the MAUI documentation, including accessing them through IQueryAttributable and QueryProperty. By default the values will be wrapped inside ShellNavigationQueryParameters, but this can be turned off in the Nucleus MVVM options (see Getting started).

Modal navigation

When navigating Nucleus will look for certain parameters in the navigation parameter IDictionary<string, object>. Currently the following parameters are supported:

Note that above parameters allow for modal presentation in Shell including deeper navigation (see the Sample Project in the repository). However this appears an underdeveloped area of Shell and might not be stable.

Avoiding double navigation

On slower devices it is a common issue that users are able to trigger multiple navigation requests by pressing a button one more than once, either too quickly or while waiting for the navigation to start. When using the CommunityToolkit (Async)RelayCommand this problem is reduced, as the Command will be disabled while it's processing. But since a navigation Task returns before it has finished navigating, it can still occur.

Nucleus offers two features to improve the navigation behavior, both are enabled by default. These are IgnoreNavigationWhenInProgress and IgnoreNavigationWithinMilliseconds, see [Configuration].

In specific cases you might want to bypass these restrictions, but not disable them fully. In those cases you can add NucleusNavigationParameters.DoNotIgnoreThisNavigationRequest in the NavigationParameters and set it to true.

Note that due to the nature of the PopupService there is no logic for avoiding multiple triggers, as it always expects a return object.

Navigation interfaces

Popups

Nucleus can display CommunityToolkit.MAUI Popups through the IPopupService. This works very similar to navigation.

Popups can be used with or without ViewModels and require registration in MauiProgram.cs using RegisterPopup<MyPopup> or RegisterPopup<MyPopup, MyPopupViewModel>.

After registration popups can be shown by passing the view type to one of the various ShowPopupAsync methods. The result can be awaited, either as an object? or a given type (note that the popup is responsible for the correct type).

Parameters can be sent through an IDictionary<string, object>, which will be passed to Init or InitAsync (see Popup interfaces). These methods will be called before showing the popup. The async variant can be configured such that it has to finish before showing the popup.

Using the IPopupAware the ViewModel can receive a reference to the popup, which is required in order to close the popup programatically. Alternatively the NucleusPopupViewModel can be used for common functionality, such as a CloseCommand and function.

Popup interfaces

Migrating from Prism

Prism is a popular library offering the same (and quite a few more) features as this library. Nucleus MVVM aims to be a simpler alternative, only adding quality-of-life MVVM features as a layer on top of MAUI. This should result in an easy to maintain library able to use the latest MAUI features.

Some compatibility classes have been included to simplify migration for projects limited to simple navigation and MVVM functionality. Nucleus MVVM is a much simpler library however, so when using more advanced Prism features this might require significant rework. Included are:

Note that the NavigationParameter compatibility class (and Prism implementation) differs from IDictionary in that it returns null when accessing a non-existing key (e.a. navigationParameters["nonKey"]). See Passing data.

Contrary to Prism, dependency injection in Nucleus uses the default Microsoft implementation, which means that apart from registering Views/ViewModels, any other registration should be done through the usual Services.AddSingleton<> and similar.

Limitations / Planned features

Support