コマンドでSPREADを操作する
SPREADの行、列、セルを生成するRow、Column、Cellクラスのメンバは、依存関係プロパティを持っていません。そのため、これらのクラスのメンバをバインディングターゲットとすることができず、ビューモデルからセルや列に対して直接バインディングができません。しかし、ボタン型セルに設定したコマンドが実行されると、Executeメソッドのパラメータからは、セルの情報を保存したCellCommandParameterオブジェクトを取得できます。また、コマンドクラスにSPREADオブジェクトを示すプロパティを追加することで、コマンドによりSPREADを操作できるようになります。ここでは、そのテクニックについて紹介します。
「値段」ボタン型セルのクリックで、4列目に値段を表示し、さらに値段が300円以上の場合は、行の背景色を変更するというコマンドを作成します。
コマンドを変更する
先ほど作成したGetPriceCommandクラスを変更します。GcSpreadGridオブジェクトを示すプロパティを追加します。
Private _spread As GcSpreadGrid Public Property spread As GcSpreadGrid Get Return _spread End Get Set(value As GcSpreadGrid) _spread = value End Set End Property
private GcSpreadGrid _spread; public GcSpreadGrid spread { get { return _spread; } set { _spread = value; } }
次に、Executeメソッドを変更します。パラメータ「parameter」から、ボタンが押されたセル情報を格納しているCellCommandParameterクラスを取得できます。CellCommandParameterクラスのCellPositionプロパティからボタンが押されたセルの行インデックスを取得できるため、変更を行いたいSPREADの行にアクセスすることができます。
Public Sub Execute(parameter As Object) Implements ICommand.Execute ' CustomCommandParameterに指定したProductViewModelオブジェクトを取得します。 Dim cp As CellCommandParameter = parameter Dim viewModel As ProductViewModel = cp.CustomCommandParameter ' ビューモデルのプロパティを更新します。 viewModel.ProductName = viewModel.SelectedProduct.Name viewModel.ProductPrice = viewModel.SelectedProduct.Price ' ボタン型セルの右側のセルに価格を表示します。 _spread(cp.CellPosition.Row, cp.CellPosition.Column + 1).Value = viewModel.SelectedProduct.Price If _spread IsNot Nothing Then ' ボタン型セルの右側のセルに価格を表示します。 _spread(cp.CellPosition.Row, cp.CellPosition.Column + 1).Value = viewModel.SelectedProduct.Price ' 価格が300円以上のものは、行の背景色を変更します。 If viewModel.SelectedProduct.Price > 300 Then _spread.Rows(cp.CellPosition.Row).Background = Brushes.Pink End If End If End Sub
public void Execute(object parameter) { // CustomCommandParameterに指定したProductViewModelオブジェクトを取得します。 CellCommandParameter cp = parameter as CellCommandParameter; ProductViewModel viewModel = cp.CustomCommandParameter as ProductViewModel; // ビューモデルのプロパティを更新します。 viewModel.ProductName = viewModel.SelectedProduct.Name; viewModel.ProductPrice = viewModel.SelectedProduct.Price; if (_spread != null) { // ボタン型セルの右側のセルに価格を表示します。 _spread[cp.CellPosition.Row, cp.CellPosition.Column + 1].Value = viewModel.SelectedProduct.Price; // 価格が300円以上のものは、行の背景色を変更します。 if (viewModel.SelectedProduct.Price > 300) { _spread.Rows[cp.CellPosition.Row].Background = Brushes.Pink; } else { _spread.Rows[cp.CellPosition.Row].Background = Brushes.White; } } }
最後に、ビューでボタン型セルを生成するとき、Commandプロパティに設定するGetPriceCommandオブジェクトのspreadプロパティにGcSpreadGridオブジェクトを設定します。
' ボタン型セルを作成します。 Dim Button As New ButtonCellType() Button.Content = "値段" ' ボタンにコマンドを設定します。 Button.Command = New GetPriceCommand() With {.spread = GcSpreadGrid1} Button.CustomCommandParameter = viewModel GcSpreadGrid1.Columns(2).CellType = Button
// ボタン型セルを作成します。 ButtonCellType button = new ButtonCellType(); button.Content = "値段"; // ボタンにコマンドを設定します。 button.Command = new GetPriceCommand() { spread = gcSpreadGrid1 }; button.CustomCommandParameter = viewModel; gcSpreadGrid1.Columns[2].CellType = button;
XAMLでは、リソースとして定義したコマンドを次のように実装します。
<Window.Resources> <local:GetPriceCommand x:Key="getPriceCommand" spread="{x:Reference gcSpreadGrid1}" /> </Window.Resources>
アプリケーションを実行し、いくつかボタン型セルをクリックすると、次のような結果となります。
コマンドのコンストラクタ引数を使用する
コマンドクラスから、ビューモデルやSPREADオブジェクトへアクセスする方法として、CustomCommandParameterプロパティの使用や、コマンドクラスへのプロパティ追加を紹介しましたが、この他に、コマンドクラスのコンストラクタ引数にオブジェクトを渡す方法も考えられます。ただし、XAMLにはコンストラクタに引数を渡す方法が用意されていないため、この方法はコードビハインドでの設定のみ有効です。まず、コマンドを定義するGetPriceCommandクラスを次のように実装します。
Public Class GetPriceCommand Implements ICommand ' SPREADとビューモデルを示すプロパティを定義します。 Private _spread As GcSpreadGrid Private _viewModel As ProductViewModel ' 引数付きコンストラクタ Public Sub New(ByRef spread As GcSpreadGrid, ByVal viewModel As ProductViewModel) _spread = spread _viewModel = viewModel End Sub Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute Return True End Function Public Sub Execute(parameter As Object) Implements ICommand.Execute Dim cp As CellCommandParameter = parameter ' ビューモデルのプロパティを更新します。 _viewModel.ProductName = _viewModel.SelectedProduct.Name _viewModel.ProductPrice = _viewModel.SelectedProduct.Price ' ボタン型セルの右側のセルに価格を表示します。 _spread(cp.CellPosition.Row, cp.CellPosition.Column + 1).Value = _viewModel.SelectedProduct.Price ' 価格が300円以上のものは、行の背景色を変更します。 If _viewModel.SelectedProduct.Price > 300 Then _spread.Rows(cp.CellPosition.Row).Background = Brushes.Pink End If End Sub End Class
public class GetPriceCommand : ICommand { public event EventHandler CanExecuteChanged; // SPREADとビューモデルを示すプロパティを定義します。 private GcSpreadGrid _spread; private ProductViewModel _viewModel; // 引数付きコンストラクタ public GetPriceCommand(GcSpreadGrid spread, ProductViewModel viewModel) { _spread = spread; _viewModel = viewModel; } public bool CanExecute(object parameter) { return true; } public void Execute(object parameter) { CellCommandParameter cp = parameter as CellCommandParameter; //ビューモデルのプロパティを更新します。 _viewModel.ProductName = _viewModel.SelectedProduct.Name; _viewModel.ProductPrice = _viewModel.SelectedProduct.Price; // ボタン型セルの右側のセルに価格を表示します。 _spread[cp.CellPosition.Row, cp.CellPosition.Column + 1].Value = _viewModel.SelectedProduct.Price; // 価格が300円以上のものは、行の背景色を変更します。 if (_viewModel.SelectedProduct.Price > 300) { _spread.Rows[cp.CellPosition.Row].Background = Brushes.Pink; } else { _spread.Rows[cp.CellPosition.Row].Background = Brushes.White; } } }
ビュー側のボタン型セルの設定は、以下の通りです。Commandプロパティに設定するGetPriceCommandクラスのコンストラクタ引数に、SPREADオブジェクトとビューモデルのオブジェクトを渡します。
' ボタン型セルを作成します。 Dim Button As New ButtonCellType() Button.Content = "値段" ' ボタンにコマンドを設定します。 Button.Command = New GetPriceCommand(GcSpreadGrid1, viewModel) GcSpreadGrid1.Columns(2).CellType = Button
// ボタン型セルを作成します。 ButtonCellType button = new ButtonCellType(); button.Content = "値段"; // ボタンにコマンドを設定します。 button.Command = new GetPriceCommand(gcSpreadGrid1, viewModel); gcSpreadGrid1.Columns[2].CellType = button;
以上で、前項と同様の動作を実現することができます。
まとめ
本記事では、SPREAD for WPFを使用して、シンプルなMVVMアプリケーションを作成する方法を紹介しました。SPREAD for WPFは、グリッドでありながら標準のDataGridやListBoxコントロールと異なり、ItemTemplateを持たないため、セルや行といった項目単位でバインディングすることができません。しかし、SPREADの持つ機能を利用して工夫することで、さまざまなコマンドを実装することも可能です。MVVMパターンの実装方法は多様で、実際の業務アプリケーションでは、もっと複雑な処理が必要となりますが、本記事での基本的な実装紹介が開発の一助となれば幸いです。