かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

WPF4.5入門 その24 「DataGridコントロール その2」

DataGridで使用可能な列

DataGridでは、列の自動生成機能とイベントのカスタマイズを使うことで簡単にデータを表示することができますが、単純なケースへの対応や、属性を利用した汎用的なデータの表示機能を開発するケース以外では、これから紹介する、自分で列を定義する方法が一般的です。DataGridで使用可能な列の中で代表的なものを以下に示します。

クラス名 説明
DataGridTextBoxColumn Bindingプロパティで指定したデータをテキストとして表示します。編集モードでは、テキストボックスを表示します。
DataGridCheckBoxColumn Bindingプロパティで指定したデータをチェックボックスとして表示します。
DataGridComboBoxColumn ItemsSourceプロパティに設定したコレクションを選択肢として表示するコンボボックスをセルに表示します。DisplayMemberPathプロパティやSelectedValuePathプロパティでコンボボックスに表示するプロパティと、選択した値として扱うプロパティを設定します。表示するデータは、SelectedValueBindingプロパティでItemsSourceプロパティで設定したコレクションで選択中の要素からSelectedValuePathで指定したプロパティの値、SelectedItemBindingプロパティでItemsSourceプロパティに設定したコレクションで選択中のものと対応づけができます。
DataGridTemplateColumn DataTemplateを使って表示内容を自由にカスタマイズできます。DataGridで指定できる列の中で一番柔軟にセル内の表示をカスタマイズできます。

DataGridの列は、以下のプロパティを使うことでヘッダーの内容をカスタマイズできます。

プロパティ 説明
object Header { get; set; } 列のヘッダーの値を取得または設定します。
DataTemplate HeaderTemplate { get; set; } 列のヘッダーの値を表示するためのテンプレートを取得または設定します。
Style HeaderStyle { get; set; } 列のヘッダーを表示するときに使用するスタイルを取得または設定します。スタイルを適用する型はDataGridHeaderColumnクラスです。

DataGridの列の使用例

DataGridの列を使ってDataGridにデータを表示します。まず、画面にDataGridを置きます。今回はDataGridの自動生成列は使用しないため、AutoGeneratedColumnsプロパティをFalseにして自動生成機能を無効化しています。

<Window x:Class="DataGridSample03.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataGridSample03"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid Name="dataGrid" AutoGenerateColumns="False">
        </DataGrid>
    </Grid>
</Window>

次に、DataGridに表示するためのクラスを定義します。以下のようにstring型と列挙型とbool型のプロパティを持つPersonクラスを作成します。

// 性別を表す列挙型
public enum Gender
{
    None,
    Men,
    Women
}
 
// DataGridに表示するデータ
public class Person
{
    // 名前
    public string Name { get; set; }
    // 性別
    public Gender Gender { get; set; }
    // 認証済みユーザーかどうか
    public bool AuthMember { get; set; }
}

MainWindowのコンストラクタで、PersonクラスのリストをDataGridのItemsSourceプロパティに設定します。

// 適当なデータ100件生成する
var data = new ObservableCollection<Person>(
    Enumerable.Range(1, 100).Select(i => new Person
    {
        Name = "田中 太郎" + i,
        Gender = i % 2 == 0 ? Gender.Men : Gender.Women,
        AuthMember = i % 5 == 0
    }));
// DataGridに設定する
this.dataGrid.ItemsSource = data;

これで、表示データの準備が出来たので列を定義してデータを表示していきます。

DataGridTextBoxColumnとDataGridCheckBoxColumnの使用

DataGridに列を定義します。DataGridの列は、Columnsプロパティに設定します。DtaGridTextColumnをNameプロパティに、DataGridCheckBoxColumnをAuthMembeプロパティにバインドしています。

<DataGrid Name="dataGrid" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="名前" Binding="{Binding Name}" />
        <DataGridCheckBoxColumn Header="認証済み" Binding="{Binding AuthMember}" />
    </DataGrid.Columns>
</DataGrid>

実行すると、以下のようになります。

セルを選択してF2キーを押すか、選択中のセルをクリックすることでセルの編集が可能です。下図は、名前の列を編集している画像になります。


DataGridComboBoxColumnの使用

次に、GenderプロパティをDataGridComboBoxColumnを使って表示します。自動生成では、enumの値がそのまま表示されていたので、ここでは日本語ラベルを表示できるようにします。まず、ComboBoxに表示するためのデータを持つクラスを作成します。ラベル用の文字列と、対応するGenderの値を持つ単純なクラスです。

namespace DataGridSample03
{
    // GenderをComboBoxに表示するためのクラス
    public class GenderComboBoxItem
    {
        // 表示用のラベル
        public string Label { get; set; }
        // 値
        public Gender Value { get; set; }
    }
}

このクラスの配列をDataGridComboBoxColumnのItemsSourceプロパティに設定してDisplayMemberPathとSelectedValuePathにLabelとValueを設定します。選択した要素の値とPersonクラスのGenderプロパティを紐づけたいのでSelectedValueBindingプロパティにGenderとのバインディングを設定します。
これまでに未登場のx:ArrayタグはType属性で指定したものの配列をXAMLで定義するためのものです。

<DataGridComboBoxColumn Header="性別" 
                        SelectedValueBinding="{Binding Gender}"
                        DisplayMemberPath="Label" 
                        SelectedValuePath="Value">
    <DataGridComboBoxColumn.ItemsSource>
        <x:Array Type="{x:Type local:GenderComboBoxItem}">
            <local:GenderComboBoxItem Label="未選択" Value="None" />
            <local:GenderComboBoxItem Label="男" Value="Men" />
            <local:GenderComboBoxItem Label="女" Value="Women" />
        </x:Array>
    </DataGridComboBoxColumn.ItemsSource>
</DataGridComboBoxColumn>

この定義を追加したDataGridの表示を以下に示します。表示データや、編集中のドロップダウンのデータが日本語になっていることが確認できます。


DataGridTemplateColumnの使用

次に、セルの表示を自由にカスタマイズできるDataGridTemplateColumnを使用します。ヘッダーとセルのテンプレートにStackPanelを使って複数の項目を表示しています。HeaderStyleを使ってHeaderTemplateで指定した表示内容を水平方向いっぱいに指定しています。この設定がないと、ヘッダーの表示が左寄せになってしまいます。CellTemplateには表示を、CellEditingTemplateには編集用のUIを設定します。どのテンプレートもStackPanelで縦並びに複数要素を表示するように設定しています。各要素の間はSeparatorコントロールを使って罫線を表示しています。

<DataGridTemplateColumn>
    <DataGridTemplateColumn.HeaderStyle>
        <Style TargetType="DataGridColumnHeader">
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        </Style>
    </DataGridTemplateColumn.HeaderStyle>
    <DataGridTemplateColumn.HeaderTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="名前" />
                <Separator />
                <TextBlock Text="認証済み" />
            </StackPanel>
        </DataTemplate>
    </DataGridTemplateColumn.HeaderTemplate>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Name}" />
                <Separator />
                <CheckBox IsEnabled="False" IsChecked="{Binding AuthMember}" />
            </StackPanel>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBox Text="{Binding Name}" />
                <Separator />
                <CheckBox IsChecked="{Binding AuthMember}" />
            </StackPanel>
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

実行結果は以下のようになります。テンプレートを使うことで1つのセルに2行のデータを表示できていることが確認できます。