本文へスキップ
BecomeCoder

C# WPFコース · 第1章 WPF ― デスクトップアプリ開発 · レッスン13

MVVM ― View と ViewModel の分離

ローカル実施

導入

**MVVM(Model-View-ViewModel)**は、WPFの標準的な設計パターンです。「見た目(View)」と「画面のロジック・状態(ViewModel)」と「業務データ(Model)」を分離し、テスト可能で保守しやすいアプリにします。第11章のSOLID・第13章のパターンがここで統合されます。

図解

flowchart LR
    V["View(XAML)<br/>見た目だけ<br/>コードビハインドは最小限"]
    VM["ViewModel<br/>画面の状態+操作<br/>(INotifyPropertyChanged / ICommand)"]
    M["Model<br/>業務データ・ルール<br/>(第22章のドメイン)"]
    V <-->|バインディング| VM
    VM --> M
    style VM fill:#fff3e0

役割分担(漏れなく)

  • View(.xaml:見た目だけを担当。{Binding}でViewModelのプロパティ・コマンドに結びつく。コードビハインド(.xaml.cs)は極力空にする
  • ViewModel:画面の状態(表示する値)と操作(コマンド)を持つ。INotifyPropertyChanged(データバインディングのレッスン)で変更通知、ICommand(イベントとコマンドのレッスン)で操作を公開。Viewを一切参照しない(=ViewModel単体でテストできる)
  • Model:業務データとルール(第22章のエンティティ・値オブジェクト)。UIを知らない
  • DataContext:ViewにどのViewModelを結びつけるかの設定。これでバインディングが機能する

XAMLサンプル(読み物)

<!-- View: DataContextにViewModelを設定し、バインドするだけ -->
<Window ...>
    <Window.DataContext>
        <local:CounterViewModel />
    </Window.DataContext>
    <StackPanel Margin="20">
        <TextBlock Text="{Binding Count}" FontSize="24" />
        <Button Content="+1" Command="{Binding IncrementCommand}" />
    </StackPanel>
</Window>
// ViewModel: 状態(Count)と操作(IncrementCommand)を持つ。Viewを知らない
public class CounterViewModel : INotifyPropertyChanged
{
    private int _count;
    public int Count
    {
        get => _count;
        set { _count = value; PropertyChanged?.Invoke(this, new(nameof(Count))); }
    }

    public ICommand IncrementCommand { get; }

    public CounterViewModel()
    {
        IncrementCommand = new RelayCommand(() => Count++);
    }

    public event PropertyChangedEventHandler? PropertyChanged;
}

詳細手順

  1. スターター141-wpf-mvvm/starter.zipを開く(View / ViewModel / Model がフォルダで分離済み)
ソリューションエクスプローラーでViews/ViewModels/Modelsフォルダに分かれたMVVM構成
MVVM構成:Views / ViewModels / Models のフォルダ分離
  1. F5で実行し、ボタンでカウントが増える(View⇄ViewModelがバインディングで連動)ことを確認する
  2. CounterViewModelにはViewへの参照が一切ないこと=単体テスト可能であることを確認する(第14章のTDDと接続)

まとめ

  • MVVMはView(見た目)・ViewModel(状態と操作)・Model(業務データ)を分離する
  • ViewModelはViewを参照しない=単体テストできる
  • バインディング+INotifyPropertyChanged+ICommandがMVVMの三種の神器

次回: 複数画面を切り替える「画面遷移」です。

テンプレート構成(教材制作用メモ)

141-wpf-mvvm/
└── starter.zip   # Views/ViewModels/Models分離 / RelayCommand / README