Aloha.Mvvm 1.0.0-beta

This is a prerelease version of Aloha.Mvvm.
dotnet add package Aloha.Mvvm --version 1.0.0-beta
                    
NuGet\Install-Package Aloha.Mvvm -Version 1.0.0-beta
                    
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="Aloha.Mvvm" Version="1.0.0-beta" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Aloha.Mvvm" Version="1.0.0-beta" />
                    
Directory.Packages.props
<PackageReference Include="Aloha.Mvvm" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Aloha.Mvvm --version 1.0.0-beta
                    
#r "nuget: Aloha.Mvvm, 1.0.0-beta"
                    
#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.
#:package Aloha.Mvvm@1.0.0-beta
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Aloha.Mvvm&version=1.0.0-beta&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Aloha.Mvvm&version=1.0.0-beta&prerelease
                    
Install as a Cake Tool

Aloha.Mvvm

<img align="right" src="https://raw.githubusercontent.com/dotnetlabs-io/Aloha.Mvvm/main/media/icon.png" />

The purpose of these projects are to simplify the creation simple/prototype/POC .NET Multi-platform App UI (MAUI) apps.

Again, these projects include a small set of functionality with the overall function being to create simple .NET MAUI apps that adhere to the Model-View-ViewModel (MVVM) design pattern.

Table of Contents

  1. Project Summary
  2. Getting Started
    1. Nuget Packages
    2. Initializing
  3. Coupling Pages to ViewModels
    1. Pages
    2. ViewModels
  4. Navigation
  5. Service Location
  6. Sample
  7. Contribute

Project Summary<a href="project-summary"></a>

  • Aloha.Mvvm is a project that helps quickly spin up a platform agnostic Model-View-ViewModel (MVVM) architectural design approach for .NET MAUI applications.

  • Aloha.Mvvm.Maui is a project that uses the Aloha.Mvvm project, and provides a set of .NET MAUI specific class/object extensions that make creating prototype and simple .NET MAUI apps much less painful.

    High-level features:

Getting Started<a href="getting-started"></a>

NuGet Packages<a href="grab-dat-nuget"></a>

Yes, there are Nuget packages for this! In fact, there are two:

  1. Aloha.Mvvm GitHub release

  2. Aloha.Mvvm.Maui GitHub release

Pro Tip: Remember that two important functions of the MVVM pattern are

  1. Maximize reuse which helps...(see point 2)
  2. Remain completely oblivious to the anything "View Level".

So, it's best to separate your MAUI app/view level code (i.e. ContentPage, ContentView, Button, etc.) from your ViewModels. At the very least, in separate projects. <./rant>

Initializing<a href="initializing"></a>

Once the Nuget packages have been installed you will need to initialize Aloha.Mvvm.Maui. Add the following line to App.xaml.cs (ideally in the constructor):

public App()
{
    InitializeComponent();

    // Add this line!
    Aloha.Mvvm.Maui.App.Init<RootViewModel>(GetType().Assembly);

    // Where "RootViewModel" is the ViewModel you want to be your MainPage
}

This accomplishes two things:

  1. Registers and couples the Views to ViewModels
  2. The Generic () assigned to the Init method establishes the MainPage (and coupled ViewModel).

Coupling Pages to ViewModels<a href="coupling-pages-to-viewmodels"></a>

Pages<a href="pages"></a>

All Base page perform two main operations upon instantiation:

  1. Set the BindingContext to the appropriate ViewModel received via generic.
  2. Executes the InitAsync method of the instantiated ViewModel. This is good for functionality you'd like executed upon page creation. InitAsync is optional - it exists as a virtual method in the base viewmodel.
BaseContentPage

Inherit from BaseContentPage from all ContentPage implementations.

XAML
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:pages="clr-namespace:Aloha.Mvvm.Maui.Pages;assembly=Aloha.Mvvm.Maui"
    xmlns:vm="clr-namespace:SampleApp.Core.ViewModels;assembly=SampleApp.Core"
    x:TypeArguments="vm:ViewModel1"
    x:Class="SampleApp.Pages.ContentPage1"
    Title="Page 1">
    <pages:BaseContentPage.Content>
           
        
                
    </pages:BaseContentPage.Content>
</pages:BaseContentPage>

Key takeaways: <a href="content-page-xaml"></a>

  1. Change ContentPage to pages:BaseContentPage ('pages' can be whatever you name it - see #2.1 below)
  2. Include XML namespaces (xmlns) declarations for
    1. Aloha.Mvvm.Maui.Pages
    2. The namespace where the ViewModel that you want to bind to this page.
  3. Add the TypeArgument for the specific ViewModel you want to bind to this page.
CS

The ContentPage implementation just needs to inherit from BaseContentPage and provide the ViewModel to be bound to the Page.

public partial class ContentPage1 : BaseContentPage<ViewModel1>
BaseFlyoutPage (inherits from FlyoutPage)
XAML
<?xml version="1.0" encoding="utf-8"?>
<pages:BaseFlyoutPage 
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:pages="clr-namespace:Aloha.Mvvm.Maui.Pages;assembly=Aloha.Mvvm.Maui"
    xmlns:vm="clr-namespace:SampleApp.Core.ViewModels;assembly=SampleApp.Core"
    x:TypeArguments="vm:RootViewModel"
    x:Class="SampleApp.Pages.RootPage"
    Title="RootFlyoutPage">
</pages:BaseFlyoutPage>

Key takeaways: See ContentPage XAML.

CS

The FlyoutPage implementation just needs to inherit from BaseFlyoutPage and provide the BaseFlyoutViewModel to be bound to the Page.

public partial class RootPage : BaseFlyoutPage<RootViewModel>
BaseTabbedPage (inherits from TabbedPage)
XAML
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseTabbedPage
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:pages="clr-namespace:Aloha.Mvvm.Maui.Pages;assembly=Aloha.Mvvm.Maui"
    xmlns:vm="clr-namespace:SampleApp.Core.ViewModels;assembly=SampleApp.Core"
    x:TypeArguments="vm:CollectionViewModel"
    x:Class="SampleApp.Pages.SampleTabbedPage"
    Title="Tabbed Page">
    <pages:BaseTabbedPage.ToolbarItems>
        <ToolbarItem Text="Switch Tab" Command="{Binding SwitchCommand}" />
    </pages:BaseTabbedPage.ToolbarItems>
</pages:BaseTabbedPage>

Key takeaways: See ContentPage XAML.

CS

The TabbedPge implementation just needs to inherit from BaseTabbedPage and provide the BaseCollectionViewModel to be bound to the Page.

public partial class SampleTabbedPage : BaseTabbedPage<CollectionViewModel>

ViewModels<a href="viewmodels"></a>

BaseNotify

BaseNotify is an abstract class that implements INotifyPropertyChanged, and provides implementations for:

PropertyChanged

public event PropertyChangedEventHandler PropertyChanged;

SetPropertyChanged

public void SetPropertyChanged(string propertyName)
{ ... }

protected virtual bool SetPropertyChanged<T>(ref T currentValue, T newValue, [CallerMemberName] string propertyName = "")
{ ... }
BaseViewModel & BaseNavigationViewModel

BaseViewModel inherits from BaseNotify, and BaseNavigationViewModel inherits from BaseViewModel.

You can inherit from the abstract class BaseNavigationViewModel for all navigation enabled ViewModels, and ViewModels you want to bind to BaseContentPage. Note that you are not limited to only binding to BaseContentPage

public class ViewModel1 : BaseViewModel

<a href="base-vm-properties"></a> Properties available:

  • IsBusy (bool)

Methods available:

  • InitAsync: a virtual method that returns a task. This method is executed upon page creation.
  • GetViewModel: returns an instantiated ViewModel via generic.
BaseMasterDetailViewModel

Inherit from abstract class BaseFlyoutViewModel for ViewModels you want to bind to a BaseFlyoutPage.

public class RootViewModel : BaseFlyoutViewModel
{
    public RootViewModel() : base() 
    { 
        var menuViewModel = GetViewModel<MenuViewModel>();
        menuViewModel.MenuItemSelected = MenuItemSelected;

        Flyout = menuViewModel;
        Detail = GetViewModel<CollectionViewModel>();
    }

    void MenuItemSelected(BaseViewModel viewModel) => SetDetail(viewModel);
}

BaseFlyoutViewModel inherits from BaseNavigationViewModel, and because of this all of the properties/methods available in BaseNavigationViewModel and BaseViewModel are also available in BaseFlyoutViewModel.

Addition properties available:

  • Master (BaseViewModel)
  • Detail (BaseViewModel)

Additional methods available:

  • SetDetail: allows you to set the Detail ViewModel.
BaseCollectionViewModel

Inherit from the abstract class BaseCollectionViewModel for ViewModels you want to bind to a BaseTabbedPage.

public class CollectionViewModel : BaseCollectionViewModel

BaseCollectionViewModel inherits from BaseNavigationViewModel, and because of this all of the properties/methods available in BaseNavigationViewModel and BaseViewModel are also available in BaseCollectionViewModel.

Addition properties available:

  • EnableNavigation (bool) - defaulted to true - determines if the page will exist within navigation stack (page)
  • SelectedIndex (int)
  • SelectedViewModel (BaseViewModel)
  • ViewModels (List<BaseViewModel>)

Navigation from one ViewModel to another is very simple. Below are samples, using 'Navigation' for an 'INavigationService' resolution, we are able to perform several actions.

Push

await Navigation.PushAsync<ViewModel>();
await Navigation.PushAsync(GetViewModel<ViewModel>());

Push Modal

await Navigation.PushModalAsync<ViewModel>();
await Navigation.PushModalAsync(GetViewModel<ViewModel>());

Pop

await Navigation.PopAsync();

Set Root

await Navigation.SetRoot<ViewModel>();
await Navigation.SetRoot(GetViewModel<ViewModel>());

Service Location<a href="service-location"></a>

ServiceContainer.cs can be used as a Service locator to register and retrieve various services.

Registration

Service.Container.Resolve<IAlertService>();

Resolving Manually

var alertService = ServiceContainer.Register<IAlertService>(new AlertService());

Sample<a href="#sample"></a>

Please feel free to clone this repository, and run the sample located here. The sample app contains a demonstration of all the major features included in Aloha.Mvvm and Aloha.Mvvm.Maui.

Contribute<a href="#contribute"></a>

Please feel free to contribute to this project by submitting PR's, issues, questions, etc. You can also contact us directly:

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  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.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.1

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Aloha.Mvvm:

Package Downloads
Aloha.Mvvm.Maui

A simple prototyping MVVM library for .NET MAUI applications.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0-beta 209 6/17/2022