avalonia-mvvm について
avalonia-mvvmは、AvaloniaアプリでCommunityToolkit.Mvvmのパターンを使うためのガイドです。ViewModel、ナビゲーション、コマンド、検証、依存性注入を扱います。
主な機能
- 01ObservableObjectによるViewModel構築
- 02属性による監視可能プロパティの作成
- 03同期・非同期コマンドの実装
- 04DataTemplatesによるViewとViewModelの対応付け
- 05依存性注入によるサービス受け渡し
- 06プロパティ検証の追加
活用シーン
- 01Avaloniaビュー用ViewModelの作成
- 02UI通知対応のプロパティとコマンドの追加
- 03ViewModelを使ったナビゲーションの設定
- 04ViewModelプロパティの検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ abdssamie/ quater --skill avalonia-mvvmインストール後、Claude Code で/avalonia-mvvmを入力して読み込まれたか確認します。
詳細
Avalonia の MVVM パターン
Avalonia アプリケーションで CommunityToolkit.Mvvm を使用する MVVM パターンの完全ガイドです。
できること
- ObservableObject 基底クラスを使用した ViewModel の実装を案内します
- [ObservableProperty] 属性を使用して監視可能なプロパティを作成する方法を紹介します
- 非同期処理や CanExecute を含む [RelayCommand] を使ったコマンドパターンを説明します
- DataTemplates を使用した View と ViewModel のマッピングについて説明します(ナビゲーションに不可欠です)
- ViewModel にサービスを渡す依存性注入のパターンを紹介します
使用する場面
次のような場合にこのスキルを使用します。
- Avalonia のビュー用に新しい ViewModel を作成する
- UI に変更を通知する監視可能なプロパティを実装する
- ユーザー操作(ボタンクリックなど)を処理するコマンドを追加する
- SukiSideMenu や ContentControl を使ったナビゲーションパターンを設定する
- ViewModel 間でサービス(ISukiToastManager など)を渡す
- ViewModel のプロパティにバリデーションを実装する
ViewModel の基底クラス
基本的な ViewModel
using CommunityToolkit.Mvvm.ComponentModel;
namespace YourApp.ViewModels;
public partial class ViewModelBase : ObservableObject
{
}
ページ ViewModel の基底クラス
using CommunityToolkit.Mvvm.ComponentModel;
namespace YourApp.ViewModels;
public abstract partial class PageViewModelBase : ViewModelBase
{
public abstract string DisplayName { get; }
public abstract string Icon { get; }
}
監視可能なプロパティ
基本的な監視可能プロパティ
[ObservableProperty]
private string _name = "";
バリデーション付き
using System.ComponentModel.DataAnnotations;
[ObservableProperty]
[Required(ErrorMessage = "Name is required")]
[MinLength(3, ErrorMessage = "Name must be at least 3 characters")]
private string _name = "";
プロパティ変更通知付き
[ObservableProperty]
private string _firstName = "";
[ObservableProperty]
private string _lastName = "";
public string FullName => $"{FirstName} {LastName}";
partial void OnFirstNameChanged(string value)
{
OnPropertyChanged(nameof(FullName));
}
partial void OnLastNameChanged(string value)
{
OnPropertyChanged(nameof(FullName));
}
コマンド
基本的なコマンド
[RelayCommand]
private void Save()
{
// Save logic
}
パラメーター付きコマンド
[RelayCommand]
private void ButtonClick(string buttonName)
{
LastButtonClicked = buttonName;
}
ビュー:
<Button Content="Save"
Command="{Binding ButtonClickCommand}"
CommandParameter="Save Button" />
非同期コマンド
[RelayCommand]
private async Task LoadDataAsync()
{
IsLoading = true;
await Task.Delay(1000);
IsLoading = false;
}
CanExecute 付きコマンド
[ObservableProperty]
private bool _isDataLoaded;
[RelayCommand(CanExecute = nameof(CanSave))]
private void Save()
{
// Save logic
}
private bool CanSave() => IsDataLoaded;
partial void OnIsDataLoadedChanged(bool value)
{
SaveCommand.NotifyCanExecuteChanged();
}
重要なパターン:DataTemplates
SukiSideMenu のように、ナビゲーションパターンで ContentControl に ViewModel を表示する場合は、ViewModel と対応する View をマッピングする DataTemplates を必ず定義する必要があります。
SukiWindow 内:
<suki:SukiWindow.DataTemplates>
<DataTemplate DataType="vm:HomePageViewModel">
<views:HomePage />
</DataTemplate>
<DataTemplate DataType="vm:SettingsPageViewModel">
<views:SettingsPage />
</DataTemplate>
</suki:SukiWindow.DataTemplates>
依存性注入
ViewModel へのサービスの受け渡し
親 ViewModel:
public partial class MainWindowViewModel : ViewModelBase
{
private readonly ISukiToastManager _toastManager;
public MainWindowViewModel()
{
_toastManager = new SukiToastManager();
Pages = new ObservableCollection<PageViewModelBase>
{
new NotificationsPageViewModeler)
};
}
}
子 ViewModel:
public partial class NotificationsPageViewModel : PageViewModelBase
{
private readonly ISukiToastManager _toastManager;
public NotificationsPageViewModel(ISukiToastManager toastManager)
{
_toastManager = toastManager;
}
}
避けるべきよくある間違い
- DataTemplates を忘れる - ViewModel と View のマッピングがないとナビゲーションは機能しません
- partial クラスを使用しない - CommunityToolkit.Mvvm では partial キーワードが必要です
- OnPropertyChanged がない - 手動で通知しないと計算プロパティは更新されません
- NotifyCanEuteChanged を呼び出さない - CanExecute 付きコマンドは自動的に再評価されません
- フィールドの命名規則を誤る - 監視可能なプロパティのフィールドは、アンダースコアで始まる private フィールドである必要があります
ベストプラクティス
- ViewModel では常に partial キーワードを使用します
- INotifyPropertyChanged を手動で実装する代わりに [ObservableProperty] を使用します
- ICommand を手動で実装する代わりに [RelayCommand] を使用します
- ナビゲーションを行う場合は、ルートウィンドウに DataTemplates を定義します
- コンストラクターインジェクションを通じてサービスを渡します
- 派生値には計算プロパティを使用します
- バリデーションが必要なプロパティにはバリデーション属性を実装します
コメント
Markdown 対応