データソースを表示および編集する為のコントロールとして「DataGrid」という標準コントロールがWPFには存在します。
データベースのテーブルデータや複数のデータを扱うコレクションクラス(LIST<T>
、Dictionary<T>
等)の要素を表示することができます。
DataGridてどうやって使ったらいいんだろう。。。
いざ、DataGrid を使おうとしたら「どうやって使ったらいいのか分からない」ということは多いのではないでしょうか。
この記事では、WPF の「DataGrid」の基本的な操作方法を紹介しています。
最後まで読めば、あなたが抱えている問題が解決するかもしれません。ぜひ全部読んで DataGrid について理解を深めてみてください。
オススメの参考書
C#の使い方が丁寧に解説しており、「基礎からしっかりと学びたい」という初心者の方にオススメの一冊です。サンプルコードも記載してあり、各章の最後に復習問題があるので理解度を確認しながら読み進めることができます。新しい C# のバージョンにも対応している書籍です。
DataGridの使い方を紹介
さっそく、DataGridを画面に表示してみましょう。DataGridを追加する方法は2通りあります。
- ツールボックスを展開してウィンドウの中にドラッグ&ドロップして配置する。
- XAMLコードに直接記述して配置する。
ここでは②の方法で追加をします。
他の UI コントロールの使い方も知りたい方はこの記事をチェック!!
ヘッダー名を追加する
ヘッダー名を設定した状態でアプリケーションを起動するには、列のデータ型を指定して、ヘッダーに表示したい名前をHeaderプロパティにセットします。
DataTableなど属性を利用した汎用的なデータの表示機能を開発するケース以外では、自分で列の型を定義する方法が一般的です。データ型の種類は4種類あります。
クラス | データの型 |
DataGridTextColumn | String |
DataGridCheckBoxColumn | Boolean |
DataGridComboBoxColumn | Enum |
DataGridHyperlinkColumn | Uri |
DataGridTemplateColumn | Control |
上記の表にあるようにデータ型によって使うクラスが違います。
String型やint型の列はセルが通常のテキストボックスになります。Boolean型の列はセルがチェックボックスになり、Enum型の列はセルがコンボボックス(ドロップダウン)で表示されるようになります。
列に表示するデータ型が決まったら、ヘッダーに表示する名前をHeaderプロパティにセットします。
<Window
x:Class="Sample.MainWindow"
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"
Title="MainWindow"
Width="450"
Height="250"
mc:Ignorable="d">
<Grid>
<DataGrid Margin="10" >
<DataGrid.Columns>
<DataGridTextColumn Header="ユーザー名" Width="120"/>
<DataGridTextColumn Header="名前" Width="120"/>
<DataGridComboBoxColumn Header="性別" Width="60"/>
<DataGridCheckBoxColumn Header="会員" Width="60"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
上記のコードを記述して実行すると次のような結果になります。
ヘッダーのスタイルをカスタマイズ
通常はデフォルトのスタイルが適用されます。ヘッダーのスタイルを変更したい場合は、CloumnHeaderStyleでプロパティを指定してスタイルを変更します。
プロパティ | 説明 |
CloumnHeaderStyle | 列のヘッダーを表示する時に使用するスタイルを取得または設定します。 スタイルを適用する型は「DataGridColumnHeader」です。 |
ここではヘッダーの項目名を中央揃えし、文字色をブルーに変更します。
<Window
x:Class="Sample.MainWindow"
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"
Title="MainWindow"
Width="450"
Height="250"
mc:Ignorable="d">
<Grid>
<DataGrid Margin="10" >
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Foreground" Value="Blue"/>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="ユーザー名" Width="120"/>
<DataGridTextColumn Header="名前" Width="120"/>
<DataGridComboBoxColumn Header="性別" Width="60"/>
<DataGridCheckBoxColumn Header="会員" Width="60"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
スタイルが変更されていることを確認してみましょう。上記のコードでデバッグすると次のような画面が表示されます。
DataGridのヘッダーを多段表示にする
通常、ヘッダーに表示できる名前は1行のみです。
WPFのDataGridは細かいカスタマイズが可能で、ヘッダーに表示する名前を2段や3段に段数分けすることが可能です。
ヘッダーを多段にする場合はTemplateプロパティを変更します。
ここでは1列目のヘッダーである「ユーザー名」に「ID」というテキストを2段目に追加します。
<Window
x:Class="Sample.MainWindow"
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"
Title="MainWindow"
Width="450"
Height="250"
mc:Ignorable="d">
<Window.Resources>
<Style x:Key="HeaderName" TargetType="DataGridColumnHeader">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridColumnHeader">
<StackPanel>
<TextBlock Text="ユーザー名" HorizontalAlignment="Center"/>
<TextBlock Text="ID" HorizontalAlignment="Center"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<DataGrid Margin="10" >
<DataGrid.Columns>
<DataGridTextColumn HeaderStyle="{StaticResource HeaderName}" Width="120"/>
<DataGridTextColumn Header="名前" Width="120" />
<DataGridComboBoxColumn Header="性別" Width="60"/>
<DataGridCheckBoxColumn Header="会員" Width="60"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
実行すると、以下のような結果が出力されます。
DataGridの列をチェックボックスで表示・非表示にする
チェックボックスがチェックされている場合は特定の列を表示し、チェックされていない場合は特定の列を非表示にするサンプルを紹介します。
列を表示・非表示を制御するプロパティは、「Visibility」です。
このVisibilityプロパティにチェックボックスのIsCheckを単純にバインドするだけでは動作しません。
bool型をVisibilityに変換してバインドすれば制御することが可能となります。(参考サイト)
<Window
x:Class="Sample.MainWindow"
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"
Title="MainWindow"
Width="450"
Height="250"
mc:Ignorable="d">
<Grid>
<Grid.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<FrameworkElement x:Key="ProxyColumnVisibility" DataContext="{Binding Path=IsChecked, ElementName=chkBoxShowColumn}" />
</Grid.Resources>
<ContentControl Content="{StaticResource ProxyColumnVisibility}" Visibility="Collapsed" />
<CheckBox
x:Name="chkBoxShowColumn"
Margin="10,10,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Content="列を表示" />
<DataGrid
x:Name="dataGrid"
Margin="10,30,10,10"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Width="120" Header="ユーザー名" />
<DataGridTextColumn Width="120" Header="名前" />
<DataGridComboBoxColumn Width="60" Header="性別" />
<DataGridCheckBoxColumn
Width="60"
Header="会員"
Visibility="{Binding DataContext, Source={StaticResource ProxyColumnVisibility}, Converter={StaticResource BooleanToVisibilityConverter}}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
実行すると、以下のような結果が出力されます。
「列を表示」にチェックをすることで、4番目の列である「会員」が表示されます。
DataGridに行を表示する
行を追加するにはコードバインドして動的にDataGridに行を追加する方法が一般的です。この方法で行を追加する場合は、XAMLとソースコードの両方に記述が必要になります。
まずVisual StudioでWPFアプリのプロジェクトに新しいクラスファイルを追加します。
このクラスにDataGridに表示するためのクラスを定義します。string型と列挙型、bool型のプロパティを持つCustomerクラスとコンストラクタを次のように記述します。
// 性別を表す列挙型
public enum GenderType
{
None,
Men,
Women
}
// DataGridに表示するデータ群
public class Customer
{
//ユーザー名
public string UserName { get; set; }
//名前
public string Name { get; set; }
//性別
public GenderType Gender { get; set; }
//会員かどうか
public bool IsMember { get; set; }
//顧客情報を保持するクラス
public Customer(string username, string name, GenderType gender, bool ismenber)
{
UserName = username;
Name = name;
Gender = gender;
IsMember = ismenber;
}
}
続けて、行を表示するためのコードをXAMLに記述します。
DataGridの各列は後述するCustomerListクラスのプロパティをバインドします。こうすることで列のヘッダーをカスタマイズした状態で表示することができます。
<DataGrid
x:Name="DataGrid1"
Margin="10"
AutoGenerateColumns="False">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Foreground" Value="Blue" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<!-- ユーザー名の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding UserName}"
Header="ユーザー名" />
<!-- 名前の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding Name}"
Header="名前" />
<!-- 性別コンボボックスの表示 -->
<DataGridComboBoxColumn
x:Name="cmbGender"
Width="60"
SelectedValueBinding="{Binding Gender, Mode=TwoWay}"
DisplayMemberPath="Value"
Header="性別"
SelectedValuePath="Key" />
<!-- 会員チェックボックスの表示 -->
<DataGridCheckBoxColumn
Width="60"
Binding="{Binding IsMember}"
Header="会員" />
</DataGrid.Columns>
</DataGrid>
MainWindowのコンストラクタでCustomerクラスのリストをDataGridのItemsSourceプロパティに設定をします。
またGenderNamesプロパティをコンボボックスのItemsSourceプロパティに設定をします。コンボボックスで選択する項目のリストを追加します。ここではEnumの定義名を表示するのではなく、ユーザーが分かる名称に変更してコンボボックスに表示をするようにしています。
using System.Collections.Generic;
using System.Windows;
namespace Sample
{
public partial class MainWindow : Window
{
private List<Customer> customers;
public MainWindow()
{
InitializeComponent();
//コンボボックスに選択できる項目のリストを追加
cmbGender.ItemsSource = GenderNames;
//DataGridに行を追加
customers = new List<Customer>
{
new Customer("yamada", "山田太郎", GenderType.Men, false),
new Customer("tanaka", "田中直樹", GenderType.Men, true),
new Customer("satouu", "佐藤七海", GenderType.Women, false),
};
DataGrid1.ItemsSource = customers;
}
// Enumの定義名変更プロパティ
public Dictionary<GenderType, string> GenderNames { get; } = new Dictionary<GenderType, string>
{
[GenderType.Men] = "男性",
[GenderType.Women] = "女性",
[GenderType.None] = "ー",
};
}
}
実行すると、以下のような結果が出力されます。
セルを選択してF2キーを押下するか、選択中のセルをクリックすることでセルの編集が可能です。
性別の列はコンボボックスになっており、次のようにアイテムの一覧の中から選択することが可能です。
DataGridに行を追加する
画面上のボタンがクリックされたら行を1行追加するサンプルを紹介します。
XAMLに次のコードを記述してボタンを追加します。
<DataGrid
x:Name="DataGrid1"
Margin="10,10,10,35"
AutoGenerateColumns="False">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Foreground" Value="Blue" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<!-- ユーザー名の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding UserName}"
Header="ユーザー名" />
<!-- 名前の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding Name}"
Header="名前" />
<!-- 性別コンボボックスの表示 -->
<DataGridComboBoxColumn
x:Name="cmbGender"
Width="60"
DisplayMemberPath="Value"
Header="性別"
SelectedValueBinding="{Binding Gender, Mode=TwoWay}"
SelectedValuePath="Key" />
<!-- 会員チェックボックスの表示 -->
<DataGridCheckBoxColumn
Width="60"
Binding="{Binding IsMember}"
Header="会員" />
</DataGrid.Columns>
</DataGrid>
<Button
x:Name="btnAdd"
Margin="10,0,0,5"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Click="btnAdd_Click"
Content="行を追加する" Height="25" />
クリックイベント内でリストに1行追加する処理を記述します。
先ほどはListクラスを使いました。単純にデータを表示するだけならList<T>で問題はありません。
しかし、DataGrid に行を追加するとなると話は別です。List<T> クラスは View への変更通知を行うことができないので、行を追加することができません。
List<T> クラスではなく、System.Collections.ObjectModel に定義されている ObservableCollection<T> クラスに変更をすることで追加することが可能になります。
List<T> クラスのままでは ItemsSource プロパティのコレクションが更新されたことが DataGrid へ通知されず、DataGrid の表示はいくらボタンを押しても更新されません。
ObservableCollection<T>クラス に変更することで、項目が追加または削除された時に、DataGrid へ通知がされて表示が更新されます。
このことを踏まえて記述した例が次になります。
public partial class MainWindow : Window
{
private ObservableCollection customers;
public MainWindow()
{
InitializeComponent();
//コンボボックスに選択できる項目のリストを追加
cmbGender.ItemsSource = GenderNames;
//DataGridに行を追加
customers = new ObservableCollection
{
new Customer("yamada", "山田太郎", GenderType.Men, false),
new Customer("tanaka", "田中直樹", GenderType.Men, true),
new Customer("satouu", "佐藤七海", GenderType.Women, false),
};
DataGrid1.ItemsSource = customers;
}
// Enumの定義名変更プロパティ
public Dictionary<GenderType, string> GenderNames { get; } = new Dictionary<GenderType, string>
{
[GenderType.Men] = "男性",
[GenderType.Women] = "女性",
[GenderType.None] = "ー",
};
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
customers.Add(new Customer("hirose", "広瀬花奈", GenderType.Women, true));
DataGrid1.ItemsSource = customers;
}
}
上記を実行すると次のように動作します。
DataGridにボタンの列を追加する
DataGridのセルにボタンを追加するには、DataGridTemplateColumnを使います。セルの中に自分で定義したコントロールを入れることができるクラスです。
書き方としては、DataGridTemplateColumn.CellTemplateの中にDataTemplateを記述し、DataTemplateの中にButtonコントロールを記述します。
また、ButtonのTagに”{Bindig}”を指定することで、クリックイベント時にその行にバインドされたデータを取得できるようになります。
<DataGrid
x:Name="DataGrid1"
Margin="10,10,10,35"
AutoGenerateColumns="False">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Foreground" Value="Blue" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<!-- ユーザー名の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding UserName}"
Header="ユーザー名" />
<!-- 名前の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding Name}"
Header="名前" />
<!-- 性別コンボボックスの表示 -->
<DataGridComboBoxColumn
x:Name="cmbGender"
Width="60"
DisplayMemberPath="Value"
Header="性別"
SelectedValueBinding="{Binding Gender, Mode=TwoWay}"
SelectedValuePath="Key" />
<!-- 会員チェックボックスの表示 -->
<DataGridCheckBoxColumn
Width="60"
Binding="{Binding IsMember}"
Header="会員" />
<!-- 編集ボタンの表示 -->
<DataGridTemplateColumn Width="45" Header="編集">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
x:Name="btnEdit"
Click="btnEdit_Click"
Content="編集"
IsEnabled="{Binding IsEdit}"
Tag="{Binding}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button
x:Name="btnAdd"
Height="25"
Margin="10,0,0,5"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Click="btnAdd_Click"
Content="行を追加する" />
ソースコード側も上記の変更に合わせて修正を行います。ボタンのイベント処理やプロパティを追加しています。
// 性別を表す列挙型
public enum GenderType
{
None,
Men,
Women
}
// DataGridに表示するデータ群
public class Customer
{
//ユーザー名
public string UserName { get; set; }
//名前
public string Name { get; set; }
//性別
public GenderType Gender { get; set; }
//会員かどうか
public bool IsMember { get; set; }
//編集するかどうか
public bool IsEdit { get; set; }
public Customer(string username, string name, GenderType gender, bool isMember, bool isEdit)
{
UserName = username;
Name = name;
Gender = gender;
IsMember = isMember;
IsEdit = isEdit;
}
}
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace Sample
{
public partial class MainWindow : Window
{
private ObservableCollection<Customer> customers;
public MainWindow()
{
InitializeComponent();
//コンボボックスに選択できる項目のリストを追加
cmbGender.ItemsSource = GenderNames;
//DataGridに行を追加
customers = new ObservableCollection<Customer>
{
new Customer("yamada", "山田太郎", GenderType.Men, false, true),
new Customer("tanaka", "田中直樹", GenderType.Men, true, false),
new Customer("satouu", "佐藤七海", GenderType.Women, false, true),
};
DataGrid1.ItemsSource = customers;
}
// Enumの定義名変更プロパティ
public Dictionary<GenderType, string> GenderNames { get; } = new Dictionary<GenderType, string>
{
[GenderType.Men] = "男性",
[GenderType.Women] = "女性",
[GenderType.None] = "ー",
};
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
customers.Add(new Customer("hirose", "広瀬花奈", GenderType.Women, true, false));
DataGrid1.ItemsSource = customers;
}
private void btnEdit_Click(object sender, RoutedEventArgs e)
{
var tag = ((Button)sender).Tag as Customer;
MessageBox.Show($"ユーザー名:{tag.UserName}\r\n名前:{tag.Name}");
}
}
}
このコードを実行すると次のような結果になります。
DataGridの列を削除する
編集ボタンの横に削除ボタンを追加して、そのボタンがクリックされた列だけを削除する方法です。
ボタンがクリックされたら、その行の項目をTagから取得します。TagはObject型のプロパティになっているので、今回の場合はCustomerでキャストします。
あとはRemoveメソッドでTagで取得した項目をcustomerのコレクションから削除すれば、ボタンがクリックされた列だけをDataGridから削除することができます。
customerはObservableCollection<T>クラスなので、コレクションから削除した項目はDataGridへ通知されて表示が更新されます。
<DataGrid
x:Name="DataGrid1"
Margin="10,10,10,35"
AutoGenerateColumns="False">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Foreground" Value="Blue" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<!-- ユーザー名の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding UserName}"
Header="ユーザー名" />
<!-- 名前の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding Name}"
Header="名前" />
<!-- 性別コンボボックスの表示 -->
<DataGridComboBoxColumn
x:Name="cmbGender"
Width="60"
DisplayMemberPath="Value"
Header="性別"
SelectedValueBinding="{Binding Gender, Mode=TwoWay}"
SelectedValuePath="Key" />
<!-- 会員チェックボックスの表示 -->
<DataGridCheckBoxColumn
Width="60"
Binding="{Binding IsMember}"
Header="会員" />
<!-- 編集ボタンの表示 -->
<DataGridTemplateColumn Width="45" Header="編集">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
x:Name="btnEdit"
Click="btnEdit_Click"
Content="編集"
IsEnabled="{Binding IsEdit}"
Tag="{Binding}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- 削除ボタンの表示 -->
<DataGridTemplateColumn Width="45" Header="削除">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
x:Name="btnDelete"
Click="btnDelete_Click"
Content="削除"
Tag="{Binding}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button
x:Name="btnAdd"
Height="25"
Margin="10,0,0,5"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Click="btnAdd_Click"
Content="行を追加する" />
削除ボタンのイベント処理を追加しています。GenderTypeクラスとCustomerクラスに変更はありません。
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace DataGrid
{
public partial class MainWindow : Window
{
private ObservableCollection customers;
public MainWindow()
{
InitializeComponent();
//コンボボックスに選択できる項目のリストを追加
cmbGender.ItemsSource = GenderNames;
//DataGridに行を追加
customers = new ObservableCollection
{
new Customer("yamada", "山田太郎", GenderType.Men, false, true),
new Customer("tanaka", "田中直樹", GenderType.Men, true, false),
new Customer("satouu", "佐藤七海", GenderType.Women, false, true),
};
DataGrid1.ItemsSource = customers;
}
// Enumの定義名変更プロパティ
public Dictionary<GenderType, string> GenderNames { get; } = new Dictionary<GenderType, string>
{
[GenderType.Men] = "男性",
[GenderType.Women] = "女性",
[GenderType.None] = "ー",
};
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
customers.Add(new Customer("hirose", "広瀬花奈", GenderType.Women, true, false));
DataGrid1.ItemsSource = customers;
}
private void btnEdit_Click(object sender, RoutedEventArgs e)
{
var tag = ((Button)sender).Tag as Customer;
MessageBox.Show($"ユーザー名:{tag.UserName}\r\n名前:{tag.Name}");
}
private void btnDelete_Click(object sender, RoutedEventArgs e)
{
var tag = ((Button)sender).Tag as Customer;
customers.Remove(tag);
}
}
}
このコードを実行すると次のような結果になります。
セルのスタイルをカスタマイズする
ヘッダーのスタイルをカスタマイズしたように、セルのスタイルもカスタマイズをすることが可能です。
列のデータ型を指定したクラス(DataGridTextColumn、DataGridCheckBoxColumn等)のElementStyleプロパティで変更をします。
ここではユーザー名の列に属するセルを赤文字にして中央揃えにカスタマイズをします。
<DataGrid
x:Name="DataGrid1"
Margin="10,10,10,35"
AutoGenerateColumns="False">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Foreground" Value="Blue" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<!-- ユーザー名の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding UserName}"
Header="ユーザー名" >
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Foreground" Value="Red" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<!-- 名前の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding Name}"
Header="名前" />
<!-- 性別コンボボックスの表示 -->
<DataGridComboBoxColumn
x:Name="cmbGender"
Width="60"
DisplayMemberPath="Value"
Header="性別"
SelectedValueBinding="{Binding Gender, Mode=TwoWay}"
SelectedValuePath="Key" />
<!-- 会員チェックボックスの表示 -->
<DataGridCheckBoxColumn
Width="60"
Binding="{Binding IsMember}"
Header="会員" />
<!-- 編集ボタンの表示 -->
<DataGridTemplateColumn Width="45" Header="編集">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
x:Name="btnEdit"
Click="btnEdit_Click"
Content="編集"
IsEnabled="{Binding IsEdit}"
Tag="{Binding}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button
x:Name="btnAdd"
Height="25"
Margin="10,0,0,5"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Click="btnAdd_Click"
Content="行を追加する" />
実行した結果は次の通りです。
セルの日本語入力を禁止する
DataGrid のセルに日本語入力ができないようにする方法です。
ここでは2つの方法を紹介します。
- IME (Input Method Editor)モードを指定する
- 入力された文字列が日本語かどうかを判定し、日本語が含まれるなら入力した文字列を削除する
IME (Input Method Editor)モードを指定する
この方法は、DataGrid のセルが編集モードに移行クリックした時に、IME の文字変換モードを強制的に半角英数字モードに切り替えて日本語の入力ができないようにします。
C# で IME を固定するので、ユーザーは文 IME モードを切り替えることはできません。
次のサンプルは、ユーザー名の列にあるセルだけ日本語入力を禁止するサンプルです。
DataGrid のセルが編集モードに移行した時に発生するPreparingCellForEdit
イベントを追加します。
<DataGrid
x:Name="DataGrid1"
Margin="10"
AutoGenerateColumns="False"
PreparingCellForEdit="DataGrid1_PreparingCellForEdit">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Foreground" Value="Blue" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<!-- ユーザー名の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding UserName}"
Header="ユーザー名" />
<!-- 名前の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding Name}"
Header="名前" />
<!-- 性別コンボボックスの表示 -->
<DataGridComboBoxColumn
x:Name="cmbGender"
Width="60"
DisplayMemberPath="Value"
Header="性別"
SelectedValueBinding="{Binding Gender, Mode=TwoWay}"
SelectedValuePath="Key" />
<!-- 会員チェックボックスの表示 -->
<DataGridCheckBoxColumn
Width="60"
Binding="{Binding IsMember}"
Header="会員" />
</DataGrid.Columns>
</DataGrid>
コードビハインドにPreparingCellForEdit
イベントが発生した時の処理を追加します。編集モードに移行したセルがユーザー名の列であるかどうかをチェックして、IME を半角英数字モードへ切り替えます。
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Sample
{
public partial class MainWindow : Window
{
private List<Customer> customers;
public MainWindow()
{
InitializeComponent();
//コンボボックスに選択できる項目のリストを追加
cmbGender.ItemsSource = GenderNames;
//DataGridに行を追加
customers = new List<Customer>
{
new Customer("yamada", "山田太郎", GenderType.Men, false),
new Customer("tanaka", "田中直樹", GenderType.Men, true),
new Customer("satouu", "佐藤七海", GenderType.Women, false),
};
DataGrid1.ItemsSource = customers;
}
// Enumの定義名変更プロパティ
public Dictionary<GenderType, string> GenderNames { get; } = new Dictionary<GenderType, string>
{
[GenderType.Men] = "男性",
[GenderType.Women] = "女性",
[GenderType.None] = "ー",
};
// セルが編集モードに移行したときに発生するイベント
private void DataGrid1_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
{
// 列がユーザー名ではない場合は戻す
if ((string)e.Column.Header != "ユーザー名")
{
return;
}
// IMEを無効にして日本語(ひらがな、全角カタカナ、半角カタカナ)を無効にする
InputMethod.SetIsInputMethodEnabled(e.EditingElement, false);
}
}
}
入力された文字列が日本語かどうかを判定する
この方法は、DataGrid のセルに文字列が入力された時に、その入力された文字列が日本語かどうかを正規表現を使って判断します。日本語だった場合は、入力された文字列を削除して日本語が入力できないようにします。
正規表現で定義されている日本語の名前によって、文字列の日本語チェックができます。
- ひらがな判定の正規表現 : ^\p{IsHiragana}*$
- カタカナ判定の正規表現 : ^\p{IsKatakana}*$
- 漢字判定の正規表現 : ^\p{IsCJKUnifiedIdeographs}*$
これらの正規表現を組み合わせて、文字列の中に1文字以上の ひらがなorカタカナor漢字 が含まれるかを判別します。
次のサンプルは、ユーザー名の列にあるセルだけ日本語入力を禁止するサンプルです。
DataGrid のセルに文字列が入力された時に発生するPreviewTextInput
イベントを追加します。
<DataGrid
PreviewTextInput="DataGrid1_PreviewTextInput"
x:Name="DataGrid1"
Margin="10"
AutoGenerateColumns="False">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Foreground" Value="Blue" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<!-- ユーザー名の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding UserName}"
Header="ユーザー名" />
<!-- 名前の表示 -->
<DataGridTextColumn
Width="120"
Binding="{Binding Name}"
Header="名前" />
<!-- 性別コンボボックスの表示 -->
<DataGridComboBoxColumn
x:Name="cmbGender"
Width="60"
DisplayMemberPath="Value"
Header="性別"
SelectedValueBinding="{Binding Gender, Mode=TwoWay}"
SelectedValuePath="Key" />
<!-- 会員チェックボックスの表示 -->
<DataGridCheckBoxColumn
Width="60"
Binding="{Binding IsMember}"
Header="会員" />
</DataGrid.Columns>
</DataGrid>
コードビハインドにPreviewTextInput
イベントが発生した時の処理を追加します。文字列が入力されたセルがユーザー名の列であるかどうかをチェックして、日本語かどうかを判断しています。
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Sample
{
public partial class MainWindow : Window
{
private List<Customer> customers;
public MainWindow()
{
InitializeComponent();
//コンボボックスに選択できる項目のリストを追加
cmbGender.ItemsSource = GenderNames;
//DataGridに行を追加
customers = new List<Customer>
{
new Customer("yamada", "山田太郎", GenderType.Men, false),
new Customer("tanaka", "田中直樹", GenderType.Men, true),
new Customer("satouu", "佐藤七海", GenderType.Women, false),
};
DataGrid1.ItemsSource = customers;
}
// Enumの定義名変更プロパティ
public Dictionary<GenderType, string> GenderNames { get; } = new Dictionary<GenderType, string>
{
[GenderType.Men] = "男性",
[GenderType.Women] = "女性",
[GenderType.None] = "ー",
};
// テキストを入力したときに発生するイベント
private void DataGrid1_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
var inputText = e.Text;
var dataGrid = (DataGrid)sender;
var header = (string)dataGrid.CurrentCell.Column.Header;
// 列がユーザー名ではない場合は戻す
if (header != "ユーザー名")
{
return;
}
// DataGridに入力した文字に日本語が含まれていないなら戻す
var isJapanese = Regex.IsMatch(inputText, @"[\p{IsHiragana}\p{IsKatakana}\p{IsCJKUnifiedIdeographs}]+");
if (!isJapanese)
{
return;
}
var itemSource = (List<Customer>)dataGrid.ItemsSource;
var selectedIndex = dataGrid.SelectedIndex;
var originalText = ((TextBox)e.OriginalSource).Text;
// DataGridのセルに入力された日本語を削除
itemSource[selectedIndex].UserName = originalText.Replace(inputText, "");
// DataGridのItemsSourceを更新
dataGrid.ItemsSource = null;
dataGrid.ItemsSource = itemSource;
}
}
}
実行した結果は次の通りです。
まとめ
この記事では、WPFのDataGridコントロールのヘッダーの表示や行の追加方法など基本的な使い方について紹介しました。
DataGridはデータを表示する際によく利用するコントロールなので、是非マスターしておきましょう。
以上、最後まで読んでいただきありがとうございました。