はじめに
下記の記事の続きとなります。
【WPF】リファクタリングで学ぶMVVM、Prism。その② ~ Model,ViewModelを作成 ~
この記事では、行追加ボタンのClick処理をリファクタリングしてきます。
リファクタリングの対象
タイトルにもありますが、追加ボタンのイベント処理をCommandを利用して、ViewからViewModelに責務を移管します。
ソースコードはこちらとなります。
<Button Grid.Column="0" Click="addBtnClick">行追加</Button>
private void addBtnClick(object sender, RoutedEventArgs e)
{
// 行を追加する
List<SampleData> records = this.xamDataGrid.DataSource as List<SampleData>;
records.Add(new SampleData());
this.xamDataGrid.DataSource = null;
this.xamDataGrid.DataSource = records;
}
リファクタリング
処理詳細を整理
まずは、addBtnClickが行っている処理を整理します。
- 行追加ボタンがクリックされたらaddBtnClickメソッドの処理を実行する。
- XamDataGridからデータソースを取得する。
- 取得したデータソースに1レコード追加する。
- 更新したデータソースを再反映させる。
これらをViewから処理移管していきましょう。
まず行追加ボタンのクリックをViewModelで感知するために、Commandの機能を利用します。
また、クリックされた後に、XamDataGridのデータソースを取得し再反映していますが、バインディングの機能を組み込めばViewModel/Modelからデータの操作が可能です。あとは、1レコードを追加するのはModelの責務となりますので、Modelにメソッドを用意したうえで、ViewModelからコールするようにしましょう。
コードリファクタリング
1. 行追加ボタンのクリック時に呼びされるCommandを作成する。
まずは、ほぼ空のCommandクラスを作成しましょう。
public class AddCommand : ICommand
{
public bool CanExecute(object parameter) { return true; }
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
}
}
ViewModelを操作できるようコンストラクタで対象のMainWindowViewModelを取得できるようにします。
private MainWindowViewModel vm;
public AddCommand(MainWindowViewModel viewModel)
{
this.vm = viewModel;
}
Commandが実行された際に動作するExcuteメソッドで、ViewModel側で用意する行追加メソッドをコールしましょう。OnAddRecord()の詳細については、次の項目にて。
public void Execute(object parameter)
{
this.vm.OnAddRecord();
}
2. 行追加ボタンのクリックイベントを削除し、1.で作成したCommandをバインディングします。
ViewModelに作成したコマンドをプロパティとして保持し、コンストラクタで初期化します。
public AddCommand AddCommand { get; set; }
public MainWindowViewModel()
{
...省略...
// コマンドを追加
this.AddCommand = new AddCommand(this);
}
Viewの行追加ボタンをクリックイベントではなく、コマンドで処理するように変更します。先ほどViewModelに追加したAddCommandプロパティとバインディングしましょう。これで、行追加ボタンがクリックされた際に、行追加ボタンのクリック > AddCommand.Execute()が実行されるようになりました。
<Button Grid.Column="0" Command="{Binding AddCommand}">行追加</Button>
3. ViewModelの行追加メソッドでは、Modelが保持する社員情報追加メソッドをコールします。
コマンド実行時(AddCommand.Execute)から呼ばれるメソッドを実装しましょう。
public void OnAddRecord()
{
// 社員情報のModelに社員情報を追加する。
this.employeeServiceModel.AddEmployee();
}
次に、Modelに社員情報を追加するメソッドを実装します。
public void AddEmployee()
{
this.Employees.Add(new SampleData());
}
4. レコードが追加されない? バインディングを見直し(ObserbabseCollection)を利用しよう。
これまでの手順を実施し、アプリケーションを起動して動作を確認してみましょう。
行追加ボタンをクリックしてもXamDataGridにレコードが追加されません。
デバッグでEmployeeServiceModel.AddEmployee()メソッドにブレークポイントを付与して確認しても、ちゃんと処理が行われていることを確認できます。
実は、コレクションを管理しているEmployeeServiceModel.Employeesの型に問題があります。
public List<SampleData> Employees { get; set; }
コレクションをバインディングで利用したい場合は、Listではなく、ObservableCollectionに変更しましょう。
ObservableCollectionはレコードの増減が発生した場合に、Viewへバインディング通知を行います。Listの場合は、バインディング通知が行われないため、レコードの追加が発生しない事象となっていました。
public ObservableCollection<SampleData> Employees { get; set; }
public ObservableCollection<SampleData> EmployeeData { get; set; }
では、もう一度アプリケーションを起動してレコードが追加されることを確認してみましょう。
OK!!
リファクタリング前後のコード
今回のコードのリファクタリング前後はこちらになります。
実施前
https://github.com/furugen/WPF-Try-Refactoring/tree/edition2
実施後
https://github.com/furugen/WPF-Try-Refactoring/tree/edition3
まとめ
MainWindow.xaml.csの行追加ボタンのClickに伴う処理を責務分割しました。
Command,ViewModel,Model,データバインディングの要素がありましたが如何でしょうか。
次は、行削除ボタンをリファクタリングしていきますが、基本的には行追加ボタンとやることは一緒ですね。
#次の記事