この記事では DataContext プロパティの強力な特徴について記載しておきます。
いきなり最終形ですが XAML ファイルは以下のとおりです。
<Window x:Class="WpfDataContextSample.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"
xmlns:local="clr-namespace:WpfDataContextSample"
mc:Ignorable="d"
Title="DataContextSample" Height="280" Width="300">
<Window.Resources>
<!-- PersonCollectionクラスのインスタンス生成 -->
<local:PersonCollection x:Key="objPersonCollection" />
</Window.Resources>
<Grid DataContext="{StaticResource objPersonCollection}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<DataGrid Grid.Row="0"
ItemsSource="{Binding People}"
AutoGenerateColumns="False"
CanUserSortColumns="False"
CanUserAddRows="False"
SelectionMode="Single"
SelectionUnit="FullRow"
>
<DataGrid.Columns>
<DataGridTextColumn Header="氏名" Binding="{Binding FullName}" Width="*" IsReadOnly="True" CanUserSort="False" />
<DataGridTemplateColumn Header="誕生日" Width="120" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding BirthDay, StringFormat=yyyy/MM/dd, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<ListBox Grid.Row="1" ItemsSource="{Binding People}" />
</Grid>
</Window>
コードビハインドは以下のとおりです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfDataContextSample
{
public class Person
{
public string FullName { get; set; }
public DateTime? BirthDay { get; set; }
public Person(string fullName, DateTime birthDay)
{
FullName = fullName;
BirthDay = birthDay;
}
// ListBoxに表示する各アイテムの文字列を整形するためにオーバーライドする
public override string ToString()
{
return FullName + "さんの誕生日は" + BirthDay.Value.ToString("yyyy年M月d日") + "です。";
}
}
public class PersonCollection
{
private List<Person> _people = new List<Person>();
public List<Person> People
{
get { return _people; }
}
public PersonCollection()
{
_people.Add(new Person("山田 太郎", new DateTime(2002, 5, 18)));
_people.Add(new Person("鈴木 花子", new DateTime(2004, 11, 6)));
_people.Add(new Person("畠山 銀次", new DateTime(1982, 7, 2)));
}
}
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
コードビハインドでは Person クラスと PersonCollection クラスを定義しています。 PersonCollection クラスには Person クラスのコレクションとなるパブリックな List<Person> 型の People プロパティを定義しています。
XAML ファイルではリソースセクションで PersonCollection クラスをインスタンス化しています。そして Grid 要素で DataContext に PersonCollection オブジェクトを設定しています。
Grid は2行に分けられており上の行には DataGrid を配置し、下の行には ListBox を配置しています。
やりたいことは DataGrid と ListBox の両方に各 Person オブジェクトの情報を表示することです。そのためにそれぞれに ItemsSource=”{Binding People}” を指定していますが、 DataGrid と ListBox には DataContext は明示的に指定されていません。これでなぜ上手くいくのでしょうか?
実は DataContext はビジュアルツリーの中を伝搬していくという特徴を持っているため、今回の場合で言うと Grid の子要素である DataGrid と ListBox の両方に引き継がれているのです。
このプログラムの実行結果は以下のとおりとなります。

なお、ListBox の各アイテムを上図の文字列形式で表示させるために Person クラスで ToString メソッドをオーバーライドしています。
今回は DataContext プロパティはビジュアルツリーの中を伝搬していくという特徴を確認しました。
コメント