SiverlightのDataGridハローワールド

SiverlightのDataGridハローワールドをやってみます。

アジェンダ

  • System.Windows.Controls.Data.dllを追加する。
  • DataGrid用のxmlns属性を追加する。
  • データグリッドをXAMLに定義する。
  • データグリッドにセットするデータクラスを定義する。
  • データグリッドのItemsSourceを初期化する。
  • データグリッドに行を追加する。
  • データグリッドの行を削除する。
  • ソースコード
  • まとめ

System.Windows.Controls.Data.dllを追加する。

VisualStudioでSilverlightアプリケーションを作成した場合、初期状態ではデータグリッドを含むアセンブリが参照されていません。そのため、最初に「参照の追加」を行います。
MSDNを調べてみますと、DataGridはSystem.Windows.Controls.Data.dllに含まれていることがわかります。
DataGrid クラス (System.Windows.Controls)
後は、[プロジェクト] メニューの [参照の追加] をクリックします。そして、[参照の追加] ダイアログ ボックスの [.NET] タブで、[System.Windows.Controls.Data] を選択すれば作業完了です。

DataGrid用のxmlns属性を追加する。

UserControlタグ内に追加する。

<!--MainPage.xaml-->
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"  

データグリッドをXAMLに定義する。

ここまで準備ができたならば、XAMLにDataGridを追加することができます。

<sdk:DataGrid x:Name="DgrBmiRecords" Height="150" Margin="5,0,5,5" IsReadOnly="True"/>

sdk」は、上で指定したXMLネームスペース名となります。
今回は、DataGrid上でデータの編集する必要がないので、IsReadOnlyをtrueにしました。

以上でデータグリッドの設置は完了しました。
これ以降の作業は、データグリッドへデータを追加したり削除したりする機能を実装します。

データグリッドにセットするデータクラスを定義する。

ItemsSourceプロパティにリスト型のインスタンスを設定すると、データグリッドにデータが表示されます。このリスト型にセットするデータクラスを定義します。
今回はこんな感じにして見ました。

public class BMIRecord
{
    /// <summary>BMIを記録した日付</summary>
    public DateTime Date { get; set; }

    /// <summary>BMI</summary>
    public double BMI { get; set; }

    /// <summary>標準値22とBMIとの差分</summary>
    public double HyojunSa { get; set; }

    /// <summary>身長</summary>
    public double Height { get; set; }

    /// <summary>体重</summary>
    public double Weight { get; set; }
}

データグリッドのItemsSourceを初期化する。

データグッドのItemsSourceにインスタンスをセットします。ItemsSourceプロパティはIEnumerable型なのでアクセスするたびにキャストするのは手間がかかるので、MainPageのフィールドに保持しておきます。

private ObservableCollection<BMIRecord> itemsSource = new ObservableCollection<BMIRecord>();

このフィールドをMainPageのコンストラクタでデータグリッドにセットします。

public MainPage()
{
    InitializeComponent();

    // データグリッドの初期化
    DgrBmiRecords.ItemsSource = this.itemsSource;

    this.RegistorEventHandler();
}

ObservableCollectionは、項目が追加、削除されたときなどにデータグリッドに通知を行ってくれるコレクションクラスです。例えば、ObservableCollectionにBMIRecordインスタンスを追加すると、データグリッドにもそのデータが表示されます。

データグリッドに行を追加する。

データグリッドにBMIRecordインスタンスを追加するロジックを記述します。タイミングは、計算ボタンが押されたときとします。

private void AddBmiRecordToDataGrid(double bmi, double height, double weight)
{
    BMIRecord record = new BMIRecord();
    record.Date = DateTime.Today;
    record.BMI = bmi;
    record.HyojunSa = bmi - 22D;
    record.Height = height;
    record.Weight = weight;

    this.itemsSource.Add(record);
}

データグリッドの行を削除する。

画面に削除ボタンを追加し、この削除ボタンがクリックされたときに、データグリッドで選択されている行を削除するロジックを記述します。

private void BtnSakujo_Click(object sender, RoutedEventArgs e)
{
    int selectedIndex = DgrBmiRecords.SelectedIndex;
    if (selectedIndex >= 0)
    {
        // SelectedIndexが0以上ならば、DataGridで行が選択されているということなので、
        // その選択行のアイテムを消す。
        this.itemsSource.RemoveAt(selectedIndex);
    }
}

ソースコード

以上で、データグリッドの実装は完了です。XAMLとcsコードの全容を書いておきます。

<UserControl x:Class="BMICalculator.MainPage"
    xmlns:contorlData="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"    
    d:DesignHeight="300" d:DesignWidth="400">

    <StackPanel x:Name="LayoutRoot">
        <StackPanel Orientation="Horizontal" Margin="5">
            <TextBlock Text="体重" Width="80" VerticalAlignment="Center" Margin="5,0"/>
            <TextBox x:Name="TbxWeight" Width="150"/>
            <TextBlock Text="Kg" VerticalAlignment="Center" Margin="5,0"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="5">
            <TextBlock Text="身長" Width="80" VerticalAlignment="Center" Margin="5,0"/>
            <TextBox x:Name="TbxHeight" Width="150"/>
            <TextBlock Text="cm" VerticalAlignment="Center" Margin="5,0"/>
        </StackPanel>
        <TextBlock x:Name="TblValidateResult" Text="" Margin="5" Foreground="Red" Height="18"/>
        <Button x:Name="BtnCalc" Content="計算" Width="80" HorizontalAlignment="Left" Margin="20,0"/>
        <StackPanel Orientation="Horizontal" Margin="5">
            <TextBlock Text="あなたのBMI" Width="80" VerticalAlignment="Center" Margin="5,0"/>
            <TextBox x:Name="TbxBMI" Width="150" IsReadOnly="True"/>
        </StackPanel>
        
        <Button x:Name="BtnSakujo" Content="削除" HorizontalAlignment="Right" Margin="5"/>
        <contorlData:DataGrid x:Name="DgrBmiRecords" Height="150" Margin="5,0,5,5" IsReadOnly="True"/>
    </StackPanel>
</UserControl>
public partial class MainPage : UserControl
{
    private ObservableCollection<BMIRecord> itemsSource = new ObservableCollection<BMIRecord>();

    public MainPage()
    {
        InitializeComponent();

        // データグリッドの初期化
        DgrBmiRecords.ItemsSource = this.itemsSource;

        this.RegistorEventHandler();
    }

    private void RegistorEventHandler()
    {
        BtnCalc.Click += new RoutedEventHandler(this.BtnCalc_Click);
        BtnSakujo.Click += new RoutedEventHandler(this.BtnSakujo_Click);
    }

    private void BtnCalc_Click(object sender, RoutedEventArgs e)
    {
        // エラー結果表示テキストブロックを初期化
        TblValidateResult.Text = string.Empty;

        // 体重kg
        double weight;
        if (!double.TryParse(TbxWeight.Text, out weight) || weight <= 0)
        {
            TblValidateResult.Text = "体重は正の数字を入力してください";
            return;
        }

        // 身長m
        double height;
        if (!double.TryParse(TbxHeight.Text, out height) || height <= 0)
        {
            TblValidateResult.Text = "身長は正の数字を入力してください";
            return;
        }

        // BMI=体重(kg)/身長(m)の二乗 
        double bmi = weight / Math.Pow(height / 100D, 2);

        // bmiをコントロールにセットする。
        TbxBMI.Text = bmi.ToString();

        // データグリッドにBMI結果を追加する。
        this.AddBmiRecordToDataGrid(bmi, height, weight);
    }

    private void AddBmiRecordToDataGrid(double bmi, double height, double weight)
    {
        BMIRecord record = new BMIRecord();
        record.Date = DateTime.Today;
        record.BMI = bmi;
        record.HyojunSa = bmi - 22D;
        record.Height = height;
        record.Weight = weight;

        this.itemsSource.Add(record);
    }

    private void BtnSakujo_Click(object sender, RoutedEventArgs e)
    {
        int selectedIndex = DgrBmiRecords.SelectedIndex;
        if (selectedIndex >= 0)
        {
            // SelectedIndexが0以上ならば、DataGridで行が選択されているということなので、
            // その選択行のアイテムを消す。
            this.itemsSource.RemoveAt(selectedIndex);
        }
    }
}

まとめ

DataGridのハローワールドを実装しました。今回は、列ヘッダーがアイテムクラス(BMIRecordクラス)のプロパティと一致する例を示しました。列を制御する例は次回以降に行う予定です。