Introduction

WPF や UWP で使っている Prism を .NET MAUI で使用するためのメモ。

サンプルソースは、GitHub に置きました。

How to use?

基本は Prism.Maui のサンプルに従えばいいが、サンプルが色々ごちゃごちゃしているので、最低限の実装に絞ったミニマルなサンプルを作った。

  • ViewModel
    • BindableBase を継承したもの
  • Moduleは使わない
  • .NET MAUI のデフォルトサンプルを MVVM に書き直すだけ

必要なもの

MAUI のサンプルプロジェクトを作ったら、サンプルのプロジェクト配下で下記を実行。

1
2
3
dotnet add package Prism.Maui --version 8.1.273-pre
dotnet add package Prism.DryIoc.Maui --version 8.1.273-pre
dotnet add package Prism.Maui.Rx --version 8.1.273-pre

現時点 (2022/10/23) でこれらはプレリリース版しか存在せず、開発者の Dan Siegel 曰く

Q. Is this Production Ready?
A. In general I would say anything serious with MAUI should wait for .NET 7. This is absolutely great for POCs.

引用: https://dansiegel.net/post/2022/06/02/prism-for-net-maui-public-beta

とのこと。
正式版は .NET 7 までお預けと思われる。

コード

View と ViewModel はそこまで重要じゃないのざっくり。
Prism のお作法に倣い、Views フォルダと ViewModels フォルダにファイルを配置するだけなので。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using Demo.ViewModels.Interfaces;

namespace Demo.ViewModels
{

internal sealed class MainPageViewModel : ViewModelBase, IMainPageViewModel
{

#region Fields

private int _Count;

#endregion

#region Constructors

public MainPageViewModel(INavigationService navigationService)
: base(navigationService)
{
this.Text = "Click me";
}

#endregion

#region IMainPageViewModel Members

private DelegateCommand _ClickCommand;

public DelegateCommand ClickCommand
{
get
{
return this._ClickCommand ??= new DelegateCommand(() =>
{
this._Count++;
this.Text = this._Count == 1 ? $"Clicked {this._Count} time" : $"Clicked {this._Count} times";
});
}
}

private string _Text;

public string Text
{
get => this._Text;
private set => this.SetProperty(ref this._Text, value);
}

#endregion

}

}

肝は下記の 2 つ

  • MauiProgram.cs の修正
  • AppShell.xaml の削除

MauiProgram.cs

公式のサンプルほぼそのままだが、Module を抜いたりしているので少しシンプル

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
using System;
using Microsoft.Maui;
using Microsoft.Maui.Controls.Hosting;
using Microsoft.Maui.Hosting;

using Demo.ViewModels;
using Demo.Views;

namespace Demo
{

public static class MauiProgram
{

#region Methods

public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>()
.UsePrism(prism =>
{
prism.ConfigureModuleCatalog(moduleCatalog =>
{
//moduleCatalog.AddModule<MauiAppModule>();
//moduleCatalog.AddModule<MauiTestRegionsModule>();
})
.RegisterTypes(containerRegistry =>
{
containerRegistry.RegisterGlobalNavigationObserver();
containerRegistry.RegisterForNavigation<MainPage>();
})
.AddGlobalNavigationObserver(context => context.Subscribe(x =>
{
if (x.Type == NavigationRequestType.Navigate)
Console.WriteLine($"Navigation: {x.Uri}");
else
Console.WriteLine($"Navigation: {x.Type}");

var status = x.Cancelled ? "Cancelled" : x.Result.Success ? "Success" : "Failed";
Console.WriteLine($"Result: {status}");

if (status == "Failed" && !string.IsNullOrEmpty(x.Result?.Exception?.Message))
Console.Error.WriteLine(x.Result.Exception.Message);
}))
.OnAppStart(navigationService =>
{
navigationService.CreateBuilder()
.AddSegment<MainPageViewModel>()
.Navigate(HandleNavigationError);
});
})
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});

return builder.Build();
}

#region Helpers

private static void HandleNavigationError(Exception ex)
{
Console.WriteLine(ex);
System.Diagnostics.Debugger.Break();
}

#endregion

#endregion

}

}

containerRegistry.RegisterGlobalNavigationObserver();AddGlobalNavigationObserver のステートメントは必須ではない。
ここを削除すれば、Prism.Maui.Rx も不要になる。

AppShell.xaml の削除

そのまま。
AppShell.xamlAppShell.xaml.cs は削除し、App.xaml.cs を下記のように修正。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using Microsoft.Maui.Controls;

namespace Demo
{

public partial class App : Application
{

#region Constructors

public App()
{
InitializeComponent();

-- MainPage = new AppShell();
}

#endregion

}

}

これをやっておかないと、実行時にエラーになります。

実行結果

MVVM にしただけなので、見た目は変わりませんが…

App

Source Code

https://github.com/takuya-takeuchi/Demo/tree/master/MAUI/01_Prism