1つ前の記事でWindowsFormを使って作ったものと似たようなものをWPFのListViewを使って作ってみようと思う。WPFのListViewのほうは、さくっとやるだけじゃ編集とかはサポートされないので、とりあえず読み取り専用で作る。
ついでに、2つ前の記事でやったようにWindows FormにWPFのコントロールを埋め込む形で1つ前の記事のWindows Formアプリケーションに埋め込んでWPFとDataGridViewの見た目の比較もできるように作ってみようと思う。
まずは、WPFのUserControlを作成する。名前はDataSetViewerにした。名前に反して汎用的な部品じゃないのを作る予定なのでご了承を。とりあえず、簡単にEmployeesテーブルの中身を出すところまでやってみる。
特に悩むことも無い。DataContextにEmployeesDataTableが設定されているという前提でぽちぽちListViewを組み立てただけだ。
<UserControl x:Class="DatabaseApp.DataSetViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<ListView ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="DeptID" DisplayMemberBinding="{Binding DeptID}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
これを、フォームの下側に貼り付ける。
フォームのロードイベントで、WPFのユーザコントロールのDataContextにEmployeesDataTableのインスタンスを設定するコードを追加する。
private void Form1_Load(object sender, EventArgs e)
{
// データ取得
this.departmentsTableAdapter.Fill(this.empMngDataSet.Departments);
this.customersTableAdapter.Fill(this.empMngDataSet.Customers);
this.employeesTableAdapter.Fill(this.empMngDataSet.Employees);
dataSetViewer1.DataContext = empMngDataSet.Employees;
}
そして、実行するとEmployeesDataTableのデータがWPFのListViewのほうにも出てる!
次は右側に、選択した従業員の顧客の情報も出してみようと思う。
これは、顧客情報を表示する側のBindingのPathに何を渡すかがわかれば簡単。DataTableのRelationの名前を渡せばOK。DataSetデザイナは、外部キーの名前をRelationの名前にしてくれるので、FK_CustomersEmployeesをBindingのPathに設定すればいける。
<UserControl x:Class="DatabaseApp.DataSetViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.ColumnDefinitions>
<!-- 従業員データ表示用の列 -->
<ColumnDefinition />
<!-- 顧客データ表示用の列 -->
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="DeptID" DisplayMemberBinding="{Binding DeptID}" />
</GridView>
</ListView.View>
</ListView>
<!-- DataTableのリレーション名をパスに指定することでバインドができる -->
<ListView Grid.Column="1" ItemsSource="{Binding FK_CustomersEmployees}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="EmployeeID" DisplayMemberBinding="{Binding DeptID}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
ばっちり出た。いい感じ。
最後に、従業員の所属する部署名を出してみようと思う。
正直、これにちょっと苦労した。というのも、ListViewのItemsSourceにはEmployeesDataTableを指定してるから、EmployeesRowがListViewの各行にあたるだろうと思ってたら実はDataRowViewのインスタンスだった。なので、何も考えずにBindingのPathにDataSetデザイナが作ってくれるDepartmentsRowプロパティのNameプロパティを指定しても、うまいこと表示されない。
DataRowViewのRowプロパティのDepartmentsRowのNameプロパティという感じでPathを指定することでうまくいった。メモメモ
<UserControl x:Class="DatabaseApp.DataSetViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.ColumnDefinitions>
<!-- 従業員データ表示用の列 -->
<ColumnDefinition />
<!-- 顧客データ表示用の列 -->
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="DeptID" DisplayMemberBinding="{Binding DeptID}" />
<!-- DataRowViewに対してBindingのPathを書く! -->
<GridViewColumn Header="DeptName" DisplayMemberBinding="{Binding Row.DepartmentsRow.Name}" />
</GridView>
</ListView.View>
</ListView>
<!-- DataTableのリレーション名をパスに指定することでバインドができる -->
<ListView Grid.Column="1" ItemsSource="{Binding FK_CustomersEmployees}" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="EmployeeID" DisplayMemberBinding="{Binding DeptID}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
実行結果。ばっちり表示できてる。
ということで、DataTableをWPFにバインドするときのメモでした。
ただ、注意しないといけないのは、DataGridViewからデータの追加をしたときにはWPFのほうも追従してくれるけど、従業員名の変更とかは追従してくれないということ。要注意や!