Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

SPREAD for WPFでMVVMパターンのアプリケーションを作成する

  • LINEで送る
  • このエントリーをはてなブックマークに追加
目次

コマンドを作成する

 現時点で、SPREADには「Code」と「Name」のデータだけが表示されていますので、選択された製品の「Price」を取得するというコマンドを作成しましょう。ビュー側でコマンドをバインディングできるのは、基本的にMenuItemやButtonといったICommandインタフェースを実装したコントロールです。SPREADでは、ボタン型セルにコマンド機能を設定することができます。ただし、ボタン型セルのCommandプロパティは、依存関係プロパティではないため、ビューモデルのプロパティとして公開されたコマンドに直接バインドすることはできません。そこで、ボタン型セルに設定するカスタムコマンドのパラメータに、ビューで作成したビューモデルのインスタンスを渡す方法を紹介します。

ビューモデルにプロパティを追加

 ProductViewModelクラスにビューとバインディングするデータをプロパティとして追加します。ここでは、選択された製品「SelectedProduct」と、製品名「ProductName」、価格「ProductPrice」の3つのプロパティを追加し、それぞれビューに変更が通知されるよう、OnPropertyChangedメソッドを実装します。

VB.NET(ProductViewModel.vb)
Private Property _productName
Public Property ProductName As String
    Get
        Return _productName
    End Get
    Set(value As String)
        _productName = value
        OnPropertyChanged("ProductName")
    End Set
End Property

Private Property _productPrice
Public Property ProductPrice As Integer
    Get
        Return _productPrice
    End Get
    Set(value As Integer)
        _productPrice = value
        OnPropertyChanged("ProductPrice")
    End Set
End Property

Private Property _selectedProduct
Public Property SelectedProduct As Product
    Get
        Return _selectedProduct
    End Get
    Set(value As Product)
        _selectedProduct = value
        OnPropertyChanged("SelectedProduct")
    End Set
End Property
C#(ProductViewModel.cs)
private string _ProductName;
public string ProductName
{
    get { return _ProductName; }
    set
    {
        _ProductName = value;
        OnPropertyChanged("ProductName");
    }
}

private int _ProductPrice;
public int ProductPrice
{
    get { return _ProductPrice; }
    set
    {
        _ProductPrice = value;
        OnPropertyChanged("ProductPrice");
    }
}

private Product _SelectedProduct;
public Product SelectedProduct
{
    get { return _SelectedProduct; }
    set
    {
        _SelectedProduct = value;
        OnPropertyChanged("SelectedProduct");
    }
}

コマンドを実装

 次に、選択された製品から、製品名と価格を取得するコマンドを実装します。コマンドはICommandインタフェースを実装します。ボタン型セルにコマンドを設定すると、Executeメソッドのパラメータからは、セルの情報を保存したCellCommandParameterオブジェクトを取得できます。CellCommandParameterクラスのCustomCommandParameterプロパティには、任意の情報を保存できます。ここでは、ProductViewModelオブジェクトを保存し、ビューモデルクラスのメンバにアクセスできるようにします。

VB.NET(ProductViewModel.vb)
‘ 次の名前空間宣言を追加しています。
‘ Imports GrapeCity.Windows.SpreadGrid

Public Class GetPriceCommand
    Implements ICommand

    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
        ' CustomCommandParameterに指定したProductViewModelオブジェクトを取得します。
        Dim cp As CellCommandParameter = parameter
        Dim viewModel As ProductViewModel = cp.CustomCommandParameter
        ' ビューモデルのプロパティを更新します。
        viewModel.ProductName = viewModel.SelectedProduct.Name
        viewModel.ProductPrice = viewModel.SelectedProduct.Price
    End Sub
End Class
C#(ProductViewModel.cs)
// 次の名前空間宣言を追加しています。
// using GrapeCity.Windows.SpreadGrid;

public class GetPriceCommand : ICommand
{
    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return true;
    }

    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;
    }
}

ビューのコントロールにバインディング

 最後に、ビューモデルで定義したプロパティや、コマンドをビューのコントロールにバインディングします。まずは、選択された製品の製品名と値段を表示する、TextBlockコントロールを次のように定義します。TextプロパティにProductViewModelクラスのProductNameとProductPriceプロパティをバインディングしています。

XAML(MainWindow.xaml)
<StackPanel Orientation="Horizontal">
    <TextBlock Text="{Binding ProductName}" FontSize="20" Foreground="Red" VerticalAlignment="Bottom"/>
    <TextBlock Text=" の値段は " VerticalAlignment="Bottom"/>
    <TextBlock Text="{Binding ProductPrice}" FontSize="20" Foreground="Red" VerticalAlignment="Bottom"/
    <TextBlock Text=" 円です。" VerticalAlignment="Bottom"/>
</StackPanel>

 次に、SPREADで選択された項目とProductViewModelクラスのSelectedProductプロパティをバインドします。SPREAD側での値選択がトリガーとなる双方向バインディングであるため、ModeプロパティはTwoWayにします。

XAML(MainWindow.xaml)
<sg:GcSpreadGrid x:Name="gcSpreadGrid1" ItemsSource="{Binding Products}" SelectedItem="{Binding SelectedProduct, Mode=TwoWay}" AutoGenerateColumns="False">
    <sg:GcSpreadGrid.Columns>
        <sg:Column>
            <sg:Column.DataField>
                <sg:PropertyDataField Property="Code" />
            </sg:Column.DataField>
        </sg:Column>
        <sg:Column>
            <sg:Column.DataField>
                <sg:PropertyDataField Property="Name" />
            </sg:Column.DataField>
        </sg:Column>
    </sg:GcSpreadGrid.Columns>
</sg:GcSpreadGrid>

 コードビハインドでの同じ設定は、以下のようなコードで可能です。

VB.NET(MainWindow.xaml.vb)
' 選択行にViewModelのSelectedProductプロパティをバインドします。
Dim selectedBinding = New Binding("SelectedProduct")
selectedBinding.Mode = BindingMode.TwoWay
GcSpreadGrid1.SetBinding(GcSpreadGrid.SelectedItemProperty, selectedBinding)
C#(MainWindow.xaml.cs)
// 選択行にViewModelのSelectedProductプロパティをバインドします。
Binding selectedBinding = new Binding("SelectedProduct");
selectedBinding.Mode = BindingMode.TwoWay;
gcSpreadGrid1.SetBinding(GcSpreadGrid.SelectedItemProperty, selectedBinding);

 そして、SPREADのボタン型セルにコマンドを設定します。ここでは、3列目にボタン型セルを設定します。ButtonCellTypeオブジェクトを作成し、CommandプロパティにはGetPriceCommandを、CustomCommandParameterプロパティには、ProductViewModelクラスのインスタンスを設定します。ボタン型セルの設定は、コードビハインドの方がわかりやすいです。

VB.NET(MainWindow.xaml.vb)
Class MainWindow
    Sub New()
        InitializeComponent()

        Dim viewModel As New ProductViewModel()
        Me.DataContext = viewModel

        ' 列の自動生成を無効にします。
        GcSpreadGrid1.AutoGenerateColumns = False

        ' Code、Name列のみ表示します。
        GcSpreadGrid1.Columns(0).DataField = New PropertyDataField() With {.Property = "Code"}
        GcSpreadGrid1.Columns(1).DataField = New PropertyDataField() With {.Property = "Name"}

        ' SPREADとビューモデルのデータコレクションをバインドします。
        Dim spreadBinding As New Binding("Products")
        GcSpreadGrid1.SetBinding(GcSpreadGrid.ItemsSourceProperty, spreadBinding)

        ' 選択行にビューモデルのSelectedProductプロパティをバインドします。
        Dim selectedBinding = New Binding("SelectedProduct")
        selectedBinding.Mode = BindingMode.TwoWay
        GcSpreadGrid1.SetBinding(GcSpreadGrid.SelectedItemProperty, selectedBinding)

        ' ボタン型セルを作成します。
        Dim Button As New ButtonCellType()
        Button.Content = "値段"
        ' ボタンにコマンドを設定します。
        Button.Command = New GetPriceCommand()
        Button.CustomCommandParameter = viewModel
        GcSpreadGrid1.Columns(2).CellType = Button
    End Sub
End Class
C#(MainWindow.xaml.cs)
public MainWindow()
{
    InitializeComponent();

    ProductViewModel viewModel = new ProductViewModel();
    this.DataContext = viewModel;

    // 列の自動生成を無効にします。
    gcSpreadGrid1.AutoGenerateColumns = false;

    // Code、Name列のみ表示します。
    gcSpreadGrid1.Columns[0].DataField = new PropertyDataField() { Property = "Code" };
    gcSpreadGrid1.Columns[1].DataField = new PropertyDataField() { Property = "Name" };

    // SPREADとビューモデルのデータコレクションをバインドします。
    Binding spreadBinding = new Binding("Products");
    gcSpreadGrid1.SetBinding(GcSpreadGrid.ItemsSourceProperty, spreadBinding);

    // 選択行にビューモデルのSelectedProductプロパティをバインドします。
    Binding selectedBinding = new Binding("SelectedProduct");
    selectedBinding.Mode = BindingMode.TwoWay;
    gcSpreadGrid1.SetBinding(GcSpreadGrid.SelectedItemProperty, selectedBinding);

    // ボタン型セルを作成します。
    ButtonCellType button = new ButtonCellType();
    button.Content = "値段";
    // ボタンにコマンドを設定します。
    button.Command = new GetPriceCommand();
    button.CustomCommandParameter = viewModel;
    gcSpreadGrid1.Columns[2].CellType = button;
}

 XAMLでボタン型セルにコマンドを設定するには、コマンドをリソースとして定義します。また、DataContextに設定しているProductViewModelクラスに名前をつけて、CustomCommandParameterプロパティに設定します。

XAML(MainWindow.xaml)
<Window.DataContext>
    <local:ProductViewModel x:Name="productViewModel" />
</Window.DataContext>
<Window.Resources>
    <local:GetPriceCommand x:Key="getPriceCommand" />
</Window.Resources>
<StackPanel>
    <sg:GcSpreadGrid x:Name="gcSpreadGrid1" ItemsSource="{Binding Products}" SelectedItem="{Binding SelectedProduct, Mode=TwoWay}" AutoGenerateColumns="False">
        <sg:GcSpreadGrid.Columns>
            <sg:Column>
                <sg:Column.DataField>
                    <sg:PropertyDataField Property="Code" />
                </sg:Column.DataField>
            </sg:Column>
            <sg:Column>
                <sg:Column.DataField>
                    <sg:PropertyDataField Property="Name" />
                </sg:Column.DataField>
            </sg:Column>
            <sg:Column>
                <sg:Column.CellType>
                    <sg:ButtonCellType Content="価格" Command="{StaticResource getPriceCommand}" CustomCommandParameter="{x:Reference productViewModel}"  />
                </sg:Column.CellType>
            </sg:Column>
        </sg:GcSpreadGrid.Columns>
    </sg:GcSpreadGrid>
</StackPanel>

 以上で完成です。実行し、知りたい製品の「値段」ボタンをクリックすると、次のように表示されます。

コマンドの実行
コマンドの実行

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

バックナンバー

連載:現役エンジニア直伝! 「現場」で使えるコンポーネント活用術(SPREAD)

もっと読む

All contents copyright © 2005-2017 Shoeisha Co., Ltd. All rights reserved. ver.1.5