1. MVVMパターンの基本概念
MVVM(Model-View-ViewModel)は、プレゼンテーション層とビジネスロジックを分離するためのアーキテクチャパターンです。このパターン実装には、データバインディングとコマンドパターンという2つの主要な技術が使用されます。
データバインディングの役割
データバインディングは、ViewとViewModel間の自動データ同期を可能にする機構です。ViewModelのプロパティ値が変更された場合、自動的にViewのUIが更新されます。これにより、手動でDOMやコントロールを更新する的必要性がなくなります。
コマンドパターンの役割
コマンドパターンは、ユーザーの操作をオブジェクトとして抽象化します。ボタンクリックやその他のユーザーインタラクションは、コマンドオブジェクトとしてViewModelに передаされます。これにより、UIロジックとビジネスロジックの分離が実現されます。
2. 実装サンプル
実践的な例:2つの数値を加算する計算機
以下に、WPFアプリケーションでのMVVM実装を示します。
ViewModel基本クラス
namespace SampleApp.ViewModels
{
public abstract class BindableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
}
}
メインViewModelクラス
namespace SampleApp.ViewModels
{
public class CalculatorViewModel : BindableBase
{
private double _firstNumber;
public double FirstNumber
{
get => _firstNumber;
set => SetProperty(ref _firstNumber, value);
}
private double _secondNumber;
public double SecondNumber
{
get => _secondNumber;
set => SetProperty(ref _secondNumber, value);
}
private double _computedResult;
public double ComputedResult
{
get => _computedResult;
set => SetProperty(ref _computedResult, value);
}
public ICommand CalculateCommand { get; }
public CalculatorViewModel()
{
CalculateCommand = new RelayCommand(ExecuteCalculation, CanExecuteCalculation);
}
private void ExecuteCalculation(object parameter)
{
ComputedResult = FirstNumber + SecondNumber;
}
private bool CanExecuteCalculation(object parameter)
{
return true;
}
}
}
コマンド実装クラス
namespace SampleApp.Commands
{
public class RelayCommand : ICommand
{
private readonly Action<object> _executeMethod;
private readonly Func<object, bool> _canExecuteMethod;
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public RelayCommand(Action<object> executeMethod, Func<object, bool> canExecuteMethod = null)
{
_executeMethod = executeMethod ?? throw new ArgumentNullException(nameof(executeMethod));
_canExecuteMethod = canExecuteMethod;
}
public bool CanExecute(object parameter)
{
return _canExecuteMethod == null || _canExecuteMethod(parameter);
}
public void Execute(object parameter)
{
_executeMethod(parameter);
}
}
}
3. 機能拡張:複数のインタラクション対応
単純なクリックイベントだけでなく、さまざまなユーザー操作にコマンドをバインドすることが可能です。以下のXAML例では、マウス関連のイベントにコマンドを関連付けています:
<Button Content="計算実行" FontSize="16">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding MouseEnterCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding MouseLeaveCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding CalculateCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
この手法により、クリックだけでなく、マウスの移動やダブルクリックなどの 다양한イベントに対して、コマンドベースの処理を追加できます。
4. MVVM採用の効果
MVVMパターンを適用することで、 단위テストの容易化、保守性の向上、コードの再利用性といった恩恵が得られます。ViewModelはUIフレームワークに依存しない形でロジックを実装できるため、ビューの変更影響をViewModelに波及させずに済みます。