MVVM は「動く」までの定型コード(ボイラープレートコード)が多く、更新通知・コマンド周りの重複が増えがちです。
CommunityToolkit.Mvvm はこの“繰り返し”をソースジェネレータで自動化します。
以下のような方に役立つ内容となっています。
- MVVMパターンのボイラープレートコードを減らしたい
- INotifyPropertyChangedの実装を簡略化したい
- ICommandの実装を簡潔に書きたい
- より保守性の高いViewModelコードを書きたい
この記事では、シンプルなカウンターアプリをベースに、CommunityToolkit.Mvvmを導入することで、どれだけコードが簡潔になるかを実践します。
MVVM解説の記事①~④から続けて見ていただくと、理解が深まるかと思います。
CommunityToolkit.Mvvmは実務でもよく使われるライブラリで、定型的なコードを大幅に削減できます。
WPF だけでなく .NET MAUI、WinUI 3、AvaloniaUI などの XAML 系 UIフレームワークでも広く活用できます。
演習のコード一式はGitHubに置いてあります。
動画も作成しています。
講義:CommunityToolkit.Mvvmによるボイラープレート削減
CommunityToolkit.Mvvmにより、どのようにボイラープレートコードが削減できるかを、Before/Afterで確認してみましょう。
Beforeコード(MVVMの基本実装)
まず、CommunityToolkit.Mvvmを使う前のコード(Beforeコード)を確認しましょう。
これまで学んできたMVVMパターンの基本を実装したシンプルなカウンターアプリを例にします。以下の構成になっています。(全コードはGitHubにあります)

前回演習のものよりシンプル(カウントするだけ)にしています。Model、ViewModel、Viewが1つずつです。
BeforeコードにおけるViewModelのコード(CounterViewModel.cs)をみてみましょう。
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using WpfCounterApp.Commands;
using WpfCounterApp.Models;
namespace WpfCounterApp.ViewModels
{
public class CounterViewModel : INotifyPropertyChanged
{
private readonly CounterModel _model;
private readonly SimpleCommand _incrementCommand;
private readonly SimpleCommand _decrementCommand;
public CounterViewModel()
{
_model = new CounterModel();
_model.ValueChanged += OnCountChanged;
_incrementCommand = new SimpleCommand(_ => _model.Increment());
_decrementCommand = new SimpleCommand(
_ => _model.Decrement(),
_ => _model.CanDecrement());
}
public int Count => _model.Value;
public ICommand IncrementCommand => _incrementCommand;
public ICommand DecrementCommand => _decrementCommand;
private void OnCountChanged()
{
OnPropertyChanged(nameof(Count));
_decrementCommand.RaiseCanExecuteChanged();
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}このコードは正しく動作しますが、MVVMパターンの実装には定型的なコード(ボイラープレート)が多く含まれています。
次に、このViewModelコードの何が課題なのかを見ていきましょう。
Beforeコードの課題
Beforeコードには、以下のような課題があります。
1.INotifyPropertyChangedの実装が冗長
ViewModelでプロパティの変更を通知するために、毎回以下のようなコードを書く必要があります。
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}すべてのViewModelで同じコードを繰り返し書くことになります。
2.コマンドの実装が煩雑
ICommandを実装したクラス(SimpleCommand)を自分で用意し、インスタンス化する必要があります。
private readonly SimpleCommand _incrementCommand;
private readonly SimpleCommand _decrementCommand;
_incrementCommand = new SimpleCommand(_ => _model.Increment());
_decrementCommand = new SimpleCommand(
_ => _model.Decrement(),
_ => _model.CanDecrement());コマンドが増えるたびに、フィールド宣言とインスタンス化のコードが増えていきます。
3.CanExecuteの変更通知が手動
コマンドの実行可否が変わったときに、手動でRaiseCanExecuteChanged()を呼ぶ必要があります。
private void OnCountChanged()
{
OnPropertyChanged(nameof(Count));
_decrementCommand.RaiseCanExecuteChanged(); // ★手動で呼び出し
}プロパティとコマンドの依存関係の管理が煩雑になりがちで、ミスが起きやすくなります。
確かに、同じようなコードを何度も書くのは面倒だし、間違えやすそうだね。
そうですね。これらの課題を解決するために、CommunityToolkit.Mvvmが用意されています。
CommunityToolkit.Mvvmとは?(Afterコード)
CommunityToolkit.Mvvm(旧名:Microsoft.Toolkit.Mvvm)は、Microsoftが提供するMVVMパターン実装を支援するライブラリです。
このライブラリには以下のような機能があります。
- ObservableObject:INotifyPropertyChangedの実装を提供する基底クラス
- ObservableProperty属性:プロパティの変更通知を自動生成
- RelayCommand属性:コマンドの実装を自動生成
- NotifyCanExecuteChangedFor属性:コマンドの実行可否の変更通知を自動化
CommunityToolkit.Mvvmは、C#のソースジェネレータ技術を使っていて、コンパイル時に定型コードを自動生成します。
ソースジェネレータ、属性って何?なんか難しそう…。
C#コードにちょっとした付加情報(属性)を記載すると、それをもとに定型コードを自動生成(ソースジェネレータが実行)する仕組みです。
ライブラリ自体は高度な仕組みで実装されていますが、使う分には属性の記述方法を把握していればOKです!一例をみてみましょう。
例えば、「ObservableObject、ObservableProperty属性」の導入によって、INotifyPropertyChanged実装が不要になります。以下のようなイメージです。
(INotifyPropertyChanged関連に絞ったBefore/Afterです)
●Before(従来)のコード
public class CounterViewModel : INotifyPropertyChanged
{
private readonly CounterModel _model;
public int Count => _model.Value;
public CounterViewModel()
{
_model = new CounterModel();
_model.ValueChanged += OnCountChanged;
}
private void OnCountChanged()
{
OnPropertyChanged(nameof(Count));
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}●After(CommunityToolkit.Mvvm利用):
public partial class CounterViewModel : ObservableObject
{
private readonly CounterModel _model;
[ObservableProperty]
private int count;
public CounterViewModel()
{
_model = new CounterModel();
_model.ValueChanged += OnCountChanged;
}
private void OnCountChanged()
{
Count = _model.Value;
}
}Afterのコード、簡潔になってる!
CommunityToolkit.Mvvmが裏側で、Afterの記述からBefore相当のコードを自動生成してくれているんですね。
それでは、演習でAfterのコード全体をつくっていきましょう!
CommunityToolkit.Mvvmについて詳しくはこちらも参考にしてください。
演習:CommunityToolkit.Mvvmの導入とコード修正
それでは、実際にCommunityToolkit.Mvvmを導入して、Beforeコードを修正してAfterコードを作成していきましょう。以下の手順で進めます。
- 手順1:NuGetパッケージのインストール
- 手順2:CounterViewModelの修正
- 手順3:SimpleCommand.csの削除
手順1:NuGetパッケージのインストール
CommunityToolkit.Mvvmをインストールします。Visual Studio上でインストールする場合は、手順については以下を参考にしてください。
プロジェクトのあるフォルダで以下のコマンドを実行する方法もあります。
dotnet add package CommunityToolkit.Mvvm手順2:CounterViewModelの修正
CounterViewModel.csを以下のように修正します。
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using WpfCounterApp.Models;
namespace WpfCounterApp.ViewModels
{
public partial class CounterViewModel : ObservableObject //★(1)
{
private readonly CounterModel _model;
public CounterViewModel()
{
_model = new CounterModel();
_model.ValueChanged += OnCountChanged;
}
[ObservableProperty] //★(2)
[NotifyCanExecuteChangedFor(nameof(DecrementCommand))] //★(3)
private int count;
[RelayCommand] //★(4)
private void Increment() => _model.Increment();
[RelayCommand(CanExecute = nameof(CanDecrement))] //★(5)
private void Decrement() => _model.Decrement();
private bool CanDecrement() => Count > 0;
private void OnCountChanged()
{
Count = _model.Value;
}
}
}以下がポイントです。
- ★(1)で、ObservableObjectを継承します。partialキーワードは、ソースジェネレータがクラス定義の残りを別ファイルで自動生成するため必須です。
- ★(2)で、小文字のフィールド(count)を宣言するだけで、大文字のプロパティ(Count)とPropertyChanged通知が自動生成されます。
- ★(3)で、Countプロパティが変更されると、指定したコマンド(DecrementCommand)のCanExecuteが自動的に再評価されます。
- ★(4) で、メソッドに属性をつけるだけで、IncrementCommandプロパティが自動生成されます。SimpleCommandのインスタンス化は不要になります。
- ★(5)で、CanExecuteパラメータで実行可否を判定するメソッドを指定できます。CanDecrementがfalseを返すと、ボタンが自動的に無効化されます。
ちなみに、自動生成されているコードを確認することもできます。例えば、Visual Studioで自動生成されたプロパティ(Count)を右クリックし「定義へ移動」をしてみましょう。
すると、以下の自動生成コードを確認できます。(もう1つのCounterViewModelクラスを自動生成しているため、partialキーワードが必要になっています。)
// <auto-generated/>
#pragma warning disable
#nullable enable
namespace WpfCounterApp.ViewModels
{
/// <inheritdoc/>
partial class CounterViewModel
{
/// <inheritdoc cref="count"/>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.4.0.0")]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public int Count
{
get => count;
set
{
if (!global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(count, value))
{
OnCountChanging(value);
OnCountChanging(default, value);
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Count);
count = value;
OnCountChanged(value);
OnCountChanged(default, value);
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Count);
DecrementCommand.NotifyCanExecuteChanged();
}
}
}
...普段、自動生成コードを開発者が意識する必要はありません。
ただ、一度これをみておくと、CommunityToolkit.Mvvmが裏で行ってくれていることのイメージを掴めるでしょう。
手順3:SimpleCommand.csの削除
CommunityToolkit.Mvvmが提供するRelayCommandを使うため、自作のSimpleCommand.csは不要になります。
SimpleCommand.csはCommandsフォルダごと削除します。
自分で作ったコマンドクラスが不要になるんだね!
アプリ実行
アプリを実行すると、Beforeコードと同じように動作します。(動作は変わりません)

コードの構造は大きく変わり、ボイラープレートコードが削減され、可読性が大幅に向上しています。
繰り返し書いていたコードがなくなって、スッキリしたね!
ViewModelのコード量も「44行→34行」(約23%)と削減できましたね。
プロパティやコマンドが増えるほど削減効果は大きくなるので、 規模の大きなアプリでは、より効果を発揮するでしょう。
まとめ
本記事では、CommunityToolkit.Mvvmを使ったMVVMパターンのボイラープレート削減について学びました。
以下のような主な機能を学びました。
- ObservableObject:INotifyPropertyChangedの実装を提供する基底クラス
- [ObservableProperty]:プロパティの変更通知を自動生成する属性
- [RelayCommand]:コマンドの実装を自動生成する属性
- [NotifyCanExecuteChangedFor]:コマンドの実行可否の変更通知を自動化する属性
CommunityToolkit.Mvvmはソースジェネレータの仕組みによって、コンパイル時に定型コードを自動生成しています。
CommunityToolkit.Mvvmは実務でも(特に新規プロジェクトで)使われていて、 WPF/MVVMアプリ開発において学ぶ価値が高いものです。
MVVM向けライブラリは、目的に応じて以下の選択肢もあります。
- Prism – 大規模アプリ開発向けの高機能MVVMライブラリ
- ReactiveUI – データの流れをストリームとして扱い、複雑な連携処理を簡単に書けるライブラリ
入門としてはCommunityToolkit.MvvmでMVVMの基礎を学ぶのがおすすめです。
引き続き、一緒にC# WPFアプリ開発を学んでいきましょう!







