はじめに
.NET MAUIを含める.NET環境では、MVVMCommunityToolKitを使用すると簡単にObserverパターンを踏襲したMVVMアーキテクチャのアプリを開発することができます。
MVVMCommunityToolKit
MVVMCommunityToolKitとはMVVMアーキテクチャをアプリへ実装させるために.NETコミュニティによって開発されたライブラリになります。
.NET MAUIだけでなく、WPFやWinFormsといったデスクトップアプリ開発でも使用することができます。
使用するとプロパティの変更が常にObserverに監視され、状態変化に応じた処理を行うことが簡単にできるようになります。
プロパティのObservable化とバインディング
画面に表示されるラベルのテキストをプロパティを使用してバインディングすることで、そのプロパティの変化をリアルタイムで反映することができます。
例えばエントリーに入力された文字をそのままラベルのテキストにバインディングしたい場合はentryDataというObservablePropertyを作ればいいだけ。
//MVVMCommunityToolKitをNuGetしてusingに指定
using CommunityToolkit.Mvvm.ComponentModel;
//ObserverblePropertyを入れるクラスはpartial classとなるので注意
public partial class MainViewModel:ObservableObject //←ViewModelクラスを作成し、ObservableObjectを継承させる
{
[ObservableProperty] //←Observable化させたいプロパティの上に記述するだけで変更が常に監視される
string entryData;
}
そしてXAMLでは、
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Sample" //←ViewModelのあるNameSpaceを追加
x:Class="Sample.MainPage">
//ViewModelをBindingContextとして指定する
<ContentPage.BindingContext>
<local:MainViewModel/>
</ContentPage.BindingContext>
<Entry Placeholder="EntryData"
Text="{Binding EntryData}"/>//←Observable化させたプロパティをBindingするだけ
<Label Text="{Binding EntryData}"/>//Entryで入力したプロパティが常に変更され表示される
//ViewModelで指定するものは頭文字を小文字とした変数。これにより作成されるプロパティは頭文字大文字なのでそのプロパティを指定するイメージ
このような形で簡単にObservable化したプロパティを作成し、画面に常に反映させることが可能となります。
コマンドについて
.NET MAUIではイベント処理をイベントハンドラーだけでなく、コマンドを利用して処理を行う方法があります。
例えば「ボタンを押して削除する」や「Deleteキーを押して削除する」など複数の入力操作に対してイベントハンドラーをすべて実装するより、「削除」コマンドで実装する方が記述も少なく済むため便利です。
MVVMCommunityToolKitではそのイベントを簡単に作成することができます。
//usingを追加
using CommunityToolkit.Mvvm.Input;
//ViewModelクラスに追加
[RelayCommand]//←コマンド化したいメソッド上に記述するだけでコマンドが作成される。(昔は[ICommand]だったが名前が変わり[RelayCommand]になった)
void Delete()
{
EntryData = string.Empty;
}
<Button Command="{Binding DeleteCommand}"/>
たったこれだけでコマンドが実装される
なぜここまで簡単なのか
なぜここまで簡単に記述できるようになったのかというと[ObservableProperty]や[RelayCommand]にはソースジェネレーターが働いており、そのソースジェネレーターがいろいろうまいこと実装してくれているため、私たちがわざわざ冗長なコードを書く必要がなくなった。
ソースジェネレーターにより書かれたソースコードはソリューションエクスプローラーの「依存関係」各プラットフォームの「アナライザー」から確認できる
//[ObservableProperty]で作り出されたソースコード
partial class MainViewModel
{
/// <inheritdoc cref="entryData"/>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.0.0.0")]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public string EntryData
{
get => entryData;
set
{
if (!global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(entryData, value))
{
OnEntryDataChanging(value);
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.EntryData);
entryData = value;
OnEntryDataChanged(value);
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.EntryData);
}
}
}
/// <summary>Executes the logic for when <see cref="EntryData"/> is changing.</summary>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.0.0.0")]
partial void OnEntryDataChanging(string value);
/// <summary>Executes the logic for when <see cref="EntryData"/> just changed.</summary>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.0.0.0")]
partial void OnEntryDataChanged(string value);
}