3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【WPF】リファクタリングで学ぶMVVM、Prism。その③ ~ 行追加ボタンのClick処理をリファクタリング ~

Last updated at Posted at 2019-04-03

はじめに

下記の記事の続きとなります。
【WPF】リファクタリングで学ぶMVVM、Prism。その② ~ Model,ViewModelを作成 ~

この記事では、行追加ボタンのClick処理をリファクタリングしてきます。

リファクタリングの対象

タイトルにもありますが、追加ボタンのイベント処理をCommandを利用して、ViewからViewModelに責務を移管します。
image.png

ソースコードはこちらとなります。

MainView.xaml
<Button Grid.Column="0" Click="addBtnClick">行追加</Button>
MainWindow.xaml.cs
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が行っている処理を整理します。

  1. 行追加ボタンがクリックされたらaddBtnClickメソッドの処理を実行する。
  2. XamDataGridからデータソースを取得する。
  3. 取得したデータソースに1レコード追加する。
  4. 更新したデータソースを再反映させる。
    これらをViewから処理移管していきましょう。

まず行追加ボタンのクリックをViewModelで感知するために、Commandの機能を利用します。
また、クリックされた後に、XamDataGridのデータソースを取得し再反映していますが、バインディングの機能を組み込めばViewModel/Modelからデータの操作が可能です。あとは、1レコードを追加するのはModelの責務となりますので、Modelにメソッドを用意したうえで、ViewModelからコールするようにしましょう。

コードリファクタリング

1. 行追加ボタンのクリック時に呼びされるCommandを作成する。

まずは、ほぼ空のCommandクラスを作成しましょう。

AddCommand.cs
public class AddCommand : ICommand
{
    public bool CanExecute(object parameter) { return true; }
    public event EventHandler CanExecuteChanged;
    public void Execute(object parameter)
    {

    }
}

ViewModelを操作できるようコンストラクタで対象のMainWindowViewModelを取得できるようにします。

AddCommand.cs
    private MainWindowViewModel vm;
    public AddCommand(MainWindowViewModel viewModel)
    {
        this.vm = viewModel;
    }

Commandが実行された際に動作するExcuteメソッドで、ViewModel側で用意する行追加メソッドをコールしましょう。OnAddRecord()の詳細については、次の項目にて。

AddCommand.cs
    public void Execute(object parameter)
    {
      this.vm.OnAddRecord();
    }

2. 行追加ボタンのクリックイベントを削除し、1.で作成したCommandをバインディングします。

ViewModelに作成したコマンドをプロパティとして保持し、コンストラクタで初期化します。

MainWindowViewModel.cs
        public AddCommand AddCommand { get; set; }

        public MainWindowViewModel()
        {
            ...省略...
            // コマンドを追加
            this.AddCommand = new AddCommand(this);
        }

Viewの行追加ボタンをクリックイベントではなく、コマンドで処理するように変更します。先ほどViewModelに追加したAddCommandプロパティとバインディングしましょう。これで、行追加ボタンがクリックされた際に、行追加ボタンのクリック > AddCommand.Execute()が実行されるようになりました。

MainView.xaml
<Button Grid.Column="0" Command="{Binding AddCommand}">行追加</Button>

3. ViewModelの行追加メソッドでは、Modelが保持する社員情報追加メソッドをコールします。

コマンド実行時(AddCommand.Execute)から呼ばれるメソッドを実装しましょう。

MainWindowViewModel.cs
        public void OnAddRecord()
        {
            // 社員情報のModelに社員情報を追加する。
            this.employeeServiceModel.AddEmployee();
        }

次に、Modelに社員情報を追加するメソッドを実装します。

EmployeeServiceModel.cs
        public void AddEmployee()
        {
            this.Employees.Add(new SampleData());
        }

4. レコードが追加されない? バインディングを見直し(ObserbabseCollection)を利用しよう。

これまでの手順を実施し、アプリケーションを起動して動作を確認してみましょう。

行追加ボタンをクリックしてもXamDataGridにレコードが追加されません。
Capture11.gif

デバッグでEmployeeServiceModel.AddEmployee()メソッドにブレークポイントを付与して確認しても、ちゃんと処理が行われていることを確認できます。

なぜでしょうか? XamDataGridのバグ?(笑)
image.png

実は、コレクションを管理しているEmployeeServiceModel.Employeesの型に問題があります。

EmployeeServiceModel.cs
public List<SampleData> Employees { get; set; }

コレクションをバインディングで利用したい場合は、Listではなく、ObservableCollectionに変更しましょう。
ObservableCollectionはレコードの増減が発生した場合に、Viewへバインディング通知を行います。Listの場合は、バインディング通知が行われないため、レコードの追加が発生しない事象となっていました。

EmployeeServiceModel.cs
public ObservableCollection<SampleData> Employees { get; set; }
MainWindowViewModel.cs
public ObservableCollection<SampleData> EmployeeData { get; set; }

では、もう一度アプリケーションを起動してレコードが追加されることを確認してみましょう。
Capture14.gif
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,データバインディングの要素がありましたが如何でしょうか。
次は、行削除ボタンをリファクタリングしていきますが、基本的には行追加ボタンとやることは一緒ですね。

#次の記事

【WPF】リファクタリングで学ぶMVVM、Prism。その④ ~ 行削除ボタンのClick処理をリファクタリング ~

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?