Burkus.Mvvm.Maui
0.1.0-preview2
Prefix Reserved
See the version list below for details.
dotnet add package Burkus.Mvvm.Maui --version 0.1.0-preview2
NuGet\Install-Package Burkus.Mvvm.Maui -Version 0.1.0-preview2
<PackageReference Include="Burkus.Mvvm.Maui" Version="0.1.0-preview2" />
paket add Burkus.Mvvm.Maui --version 0.1.0-preview2
#r "nuget: Burkus.Mvvm.Maui, 0.1.0-preview2"
// Install Burkus.Mvvm.Maui as a Cake Addin #addin nuget:?package=Burkus.Mvvm.Maui&version=0.1.0-preview2&prerelease // Install Burkus.Mvvm.Maui as a Cake Tool #tool nuget:?package=Burkus.Mvvm.Maui&version=0.1.0-preview2&prerelease
Navigation - Parameter Passing - Lifecycle Events - Native Dialogs - Testability
Burkus.Mvvm.Maui (experimental)
Burkus.Mvvm.Maui
is an MVVM (Model–view–viewmodel) framework for .NET MAUI. The library has some key aims it wants to provide:
- Be lightweight and only provide the parts of MVVM that MAUI needs 👟
- MAUI has dependency injection built-in now,
Burkus.Mvvm.Maui
takes advantage of this. CommunityToolkit.Mvvm
provides excellent: commanding, observable properties, source generating attributes, and fast messaging.Burkus.Mvvm.Maui
does not compete with any of this and the idea is that you should pair both libraries together (or another library that does those things). This is not forced upon you, however.- MAUI [without Shell] needs: navigation, passing parameters, lifecycle events, and modals.
Burkus.Mvvm.Maui
wants to provide these things.
- MAUI has dependency injection built-in now,
- Be unit testable 🧪
- .NET MAUI itself is difficult to unit test outside the box and sometimes third-party MAUI libraries can be too.
- You should be easily able to assert that when you press a button, that the command that fires navigates you to a particular page.
- Be easy to understand and setup 📄
- The APIs and syntax should be easy to setup/understand
- The library should be well documented (the current plan is to document the library in this README)
- Be dependable for the future 🔮
- The library is OSS and released under the MIT license. Contributors do not need to sign a CLA.
- Individuals and businesses can fork it if it ever doesn't meet their needs.
⚠️ WARNING: Burkus.Mvvm.Maui
is currently an experimental library. The API will change frequently and there will be frequent backwards compatibility breaking changes. This library will be versioned as "0.y.z" until a well-liked, stable API has been found. Only then would a version "1.y.z" and beyond be released.
Documentation 📗
See the DemoApp
in the /samples
folder of this repository for a full example of this library in action. The demo app has examples of different types of navigation, configuring the library, using lifecycle events, passing parameters, and showing native dialogs.
Getting started
- Install
Burkus.Mvvm.Maui
into your main MAUI project from NuGet: https://www.nuget.org/packages/Burkus.Mvvm.Maui - In your shared project's
App.xaml.cs
, remove any line whereMainPage
is set to aPage
or anAppShell
. MakeApp
inherit fromBurkusMvvmApplication
. You should be left with a simplerApp
class like this:
public partial class App : BurkusMvvmApplication
{
public App()
{
InitializeComponent();
}
}
- Update
App.xaml
in your shared project to be aburkus:BurkusMvvmApplication
.
<?xml version="1.0" encoding="UTF-8" ?>
<burkus:BurkusMvvmApplication
...
xmlns:burkus="http://burkus.co.uk">
...
</burkus:BurkusMvvmApplication>
- In your
MauiProgram.cs
file, call.UseBurkusMvvm()
in your builder creation e.g.:
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder()
.UseMauiApp<App>()
.UseBurkusMvvm(burkusMvvm =>
{
burkusMvvm.OnStart(async (navigationService) =>
{
await navigationService.Push<LoginPage>();
});
})
...
- 💡 RECOMMENDED: This library pairs great with the amazing
CommunityToolkit.Mvvm
. Follow its Getting started guide to add it.
Registering views, viewmodels, and services
A recommended way to register your views, viewmodels, and services is by creating extension methods in your MauiProgram.cs
file.
public static MauiAppBuilder RegisterViewModels(this MauiAppBuilder mauiAppBuilder)
{
mauiAppBuilder.Services.AddTransient<HomeViewModel>();
mauiAppBuilder.Services.AddTransient<SettingsViewModel>();
return mauiAppBuilder;
}
public static MauiAppBuilder RegisterViews(this MauiAppBuilder mauiAppBuilder)
{
mauiAppBuilder.Services.AddTransient<HomePage>();
mauiAppBuilder.Services.AddTransient<SettingsPage>();
return mauiAppBuilder;
}
public static MauiAppBuilder RegisterServices(this MauiAppBuilder mauiAppBuilder)
{
mauiAppBuilder.Services.AddSingleton<IWeatherService, WeatherService>();
return mauiAppBuilder;
}
Dependency injection
View setup
In your xaml
page, you need to use the ResolveBindingContext
markup extension so that the correct viewmodel will be resolved for your view during navigation.
<ContentPage
...
xmlns:burkus="http://burkus.co.uk"
xmlns:vm="clr-namespace:DemoApp.ViewModels"
BindingContext="{burkus:ResolveBindingContext x:TypeArguments=vm:HomeViewModel}"
...>
Complete example (x:DataType
has also been added for improved performance and better auto-complete suggestions in XAML):
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="DemoApp.Views.HomePage"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:burkus="http://burkus.co.uk"
xmlns:vm="clr-namespace:DemoApp.ViewModels"
x:DataType="vm:HomeViewModel"
BindingContext="{burkus:ResolveBindingContext x:TypeArguments=vm:HomeViewModel}">
...
</ContentPage>
Viewmodel setup
In your viewmodel's constructor, include references to any services you want to be automatically resolved. In the below example, Burkus.Mvvm.Maui
's INavigationService
and an example service called IExampleService
will be resolved when navigating to HomeViewModel
.
public HomeViewModel(
INavigationService navigationService,
IExampleService exampleService)
{
this.navigationService = navigationService;
this.exampleService = exampleService;
}
ServiceResolver (not recommended)
You can use the static class ServiceResolver
to resolve services elsewhere in your application (for example, inside of converters and inside of xaml.cs
files). You should use this sparingly as it will make your code less unit-testable.
Typed service resolution:
ServiceResolver.Resolve<IExampleService>();
Untyped service resolution:
ServiceResolver.Resolve(IExampleService);
Choosing the start page of your app
It is possible to have a service that decides which page is most appropriate to navigate to. This service could decide to:
- Navigate to the "Terms & Conditions" page if the user has not agreed to the latest terms yet
- Navigate to the "Signup / Login" page if the user is logged out
- Navigate to the "Home" page if the user has used the app before and doesn't need to do anything
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder()
.UseMauiApp<App>()
.UseBurkusMvvm(burkusMvvm =>
{
burkusMvvm.OnStart(async (navigationService) =>
{
var appStartupService = ServiceResolver.Resolve<IAppStartupService>();
await appStartupService.NavigateToFirstPage();
});
})
...
Lifecycle events and passing parameters
INavigatedEvents
If your viewmodel inherits from this interface, the below events will trigger for it.
OnNavigatedTo(parameters)
- You can use this lifecycle event to retrieve parameters passed to this page
- Is similar to MAUI's
Page
' OnNavigatedTo event.
public async Task OnNavigatedTo(NavigationParameters parameters) { Username = parameters.GetValue<string>("username"); }
OnNavigatedFrom(parameters)
- Allows the page you are leaving to add additional parameters to the page you are navigating to
- Is similar to MAUI's
Page
's OnNavigatedFrom event.
public async Task OnNavigatedFrom(NavigationParameters parameters) { parameters.Add("username", username); }
INavigatingEvents
If your viewmodel inherits from this interface, the below events will trigger for it.
OnNavigatingFrom(parameters)
- Allows the page you are leaving to add additional parameters to the page you are navigating to
- Is similar to MAUI's
Page
's OnNavigatingFrom event.
public async Task OnNavigatingFrom(NavigationParameters parameters) { parameters.Add("username", username); }
Reserved navigation parameters
Several parameter keys have been pre-defined and are using by the Burkus.Mvvm.Maui
library to adjust how navigation is performed.
ReservedNavigationParameters.UseAnimatedNavigation
- Should an animation be used during the navigation?
- Defaults to:
true
ReservedNavigationParameters.UseModalNavigation
- Should the navigation be performed modally?
- Defaults to:
false
The NavigationParameters
object exposes some handy properties .UseAnimatedNavigation
and .UseModalNavigation
so you can easily set or check the value of these properties.
Dialog service
IDialogService
is automatically registered by .UseBurkusMvvm(...)
. It is a testable service that is an abstraction over the MAUI alerts/pop-ups/prompts/action sheets.
Register the service in your viewmodel constructor:
public HomeViewModel(
IDialogService dialogService,
INavigationService navigationService)
{
this.dialogService = dialogService;
this.navigationService = navigationService;
}
This is a simple example of showing an error alert message with the DialogService
:
dialogService.DisplayAlert(
"Error",
"You must enter a username.",
"OK");
See the IDialogService interface in the repository for all the possible method options.
Advanced / complexities
The below are some things of note that may help prevent issues from arising:
- When you inherit from
BurkusMvvmApplication
, theMainPage
of the app will be automatically set to aNavigationPage
. This means the first page you push can be aContentPage
rather than needing to push aNavigationPage
. This may change in the future.
Roadmap 🛣️
- URL-based navigation
- View and viewmodel auto-registration
- Popup pages
- Nested viewmodels
- OnNavigatingTo()
- IPageVisibilityEvents
- ...and more
Create an issue to add your own suggestions.
Contributing 💁♀️
Contributions are very welcome! Please see the contributing guide to get started.
License 🪪
The project is distributed under the MIT license. Contributors do not need to sign a CLA.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net7.0
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 |
---|---|---|
0.2.1-preview2 | 336 | 1/1/2024 |
0.2.1-preview1 | 201 | 11/18/2023 |
0.2.0 | 339 | 11/14/2023 |
0.2.0-preview8 | 101 | 11/11/2023 |
0.2.0-preview7 | 103 | 11/11/2023 |
0.2.0-preview6 | 108 | 11/11/2023 |
0.2.0-preview5 | 116 | 11/11/2023 |
0.2.0-preview4 | 155 | 10/23/2023 |
0.2.0-preview3 | 123 | 10/18/2023 |
0.2.0-preview2 | 109 | 10/16/2023 |
0.2.0-preview1 | 117 | 10/14/2023 |
0.1.0 | 169 | 10/14/2023 |
0.1.0-preview7 | 97 | 10/13/2023 |
0.1.0-preview6 | 110 | 10/12/2023 |
0.1.0-preview5 | 104 | 10/12/2023 |
0.1.0-preview4 | 122 | 10/7/2023 |
0.1.0-preview3 | 100 | 10/5/2023 |
0.1.0-preview2 | 111 | 10/5/2023 |
0.1.0-preview1 | 108 | 10/5/2023 |