●Bindingマークアップ拡張の書き方
これまでの例では、Bindingマークアップ拡張を単に「{Binding X}」というように記述してきたが、Bindingマークアップ拡張にはさまざまなプロパティがあり、データ・バインディングの挙動を細かく設定することができる。以下、主要なものをいくつか紹介していく。
○データ・バインディングの向きとタイミング
Modeプロパティで、データ・バインディングの向きとタイミングを指定できる。Modeプロパティに対して設定できる値は以下のとおりである。
当然、TwoWayやOneWayToSourceを指定するためには、ソース・プロパティが書き込み可能である(setアクセサを持っている)必要がある。また、TwoWayやOneWayToSourceを指定した際には、変更をソース・プロパティに反映させるタイミングをUpdateSourceTriggerプロパティで指定できる。UpdateSourceTriggerプロパティに設定できる値は以下のとおりである。
○バインディング・ソースのパスの書き方
Pathプロパティで、バインディング・ソースのパスを指定する。Pathプロパティは省略形で書くことができ、これまで用いてきた、
{Binding X}
という書き方は、
{Binding Path=X}
と同じ意味である。Pathプロパティでは、以下のような構文でパス指定が可能である。
例えば、List 3に示すように、階層的なデータをDataContextプロパティに渡した場合を考えてみよう。
this.DataContext = new
{
管理者 = new { 姓 = "岩永", 名 = "信之" },
コンテンツ = new[]
{
new { タイトル = "C# 入門", URL = "csharp" },
new { タイトル = "信号処理", URL = "dsp" },
new { タイトル = "力学", URL = "dynamics" },
}
};
Me.DataContext = New With
{
.管理者 = New With {.姓 = "岩永", .名 = "信之"},
.コンテンツ =
{
New With {.タイトル = "C# 入門", .URL = "csharp"},
New With {.タイトル = "信号処理", .URL = "dsp"},
New With {.タイトル = "力学", .URL = "dynamics"}
}
}
このとき、List 4に示すようなXAMLコードを書くと、Figure 5に示すような表示結果が得られる。
……省略……
<StackPanel x:Name="panel" Canvas.Left="99">
<!-- 階層的なプロパティ指定 -->
<TextBlock Text="{Binding 管理者.姓}"/>
<!-- インデクサー -->
<TextBlock Text="{Binding コンテンツ[1].URL}"/>
<!-- 添付プロパティ -->
<TextBlock
Text="{Binding ElementName=panel, Path=(Canvas.Left)}"/>
</StackPanel>
……省略……
○コレクション走査パスの指定
Pathプロパティでは、「{Binding Path=List/X}」というように「/」でつなぐことで、リストボックスなどで選択された行のプロパティを表示することができる(コレクションを走査して、選択中の要素を拾い出してくれる)。
前節と同様に、List 3に示すデータをDataContextプロパティに渡した場合、List 5に示すようなXAMLコードを書くとFigure 6に示すような表示結果が得られる。
……省略……
<StackPanel>
<!-- 「/」による選択行の表示を働かせるためには
IsSynchronizedWithCurrentItemプロパティの指定が必要 -->
<DataGrid ItemsSource="{Binding Path=コンテンツ}"
IsSynchronizedWithCurrentItem="True" />
<!-- DataGridコントロールで選択されている行の
[タイトル]プロパティが表示される -->
<TextBlock Text="{Binding Path=コンテンツ/タイトル}" />
</StackPanel>
……省略……
○バインディング・ソースの明示的指定
特に何も指定しない場合、バインディング・ソースは、UI要素のDataContextプロパティに与えられたオブジェクトになる。一方で、Bindingマークアップ拡張のSourceプロパティを設定することで、バインディング・ソースを明示的に指定することもできる。
例えば、List 6に示すように、静的プロパティをバインディング・ソースに指定するなどの用途で利用する。
……省略……
<StackPanel>
<TextBlock Text="{Binding Source={x:Static Application.Current},
Path=StartupUri}" />
</StackPanel>
……省略……
Sourceプロパティのほかに、後述するElementNameプロパティやRelativeSourceプロパティでもバインディング・ソースを選択できるが、これら3つのプロパティを同時に指定することはできない。
○XPath
バインディング・ソースがXMLデータの場合、PathプロパティではなくXPathプロパティを利用する。
XPathプロパティには、(XMLに付随するパス指定言語である)XPath言語(XML Path Language)でクエリを記述する。XPathクエリの書き方については本稿の範囲を超えるため、詳細は割愛し、例のみをList 7に示す。
……省略……
<Grid>
<Grid.Resources>
<XmlDataProvider x:Key="Pages" XPath="Pages">
<x:XData>
<Pages xmlns="">
<Page Title="C# 入門" Url ="csharp" />
<Page Title="信号処理" Url ="dsp" />
<Page Title="力学" Url ="dynamics" />
</Pages>
</x:XData>
</XmlDataProvider>
</Grid.Resources>
<ListBox ItemsSource=
"{Binding Source={StaticResource Pages}, XPath=Page}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=@Title}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
……省略……
○ほかのUI要素の参照
場合によっては、モデルなどのデータ・ソースを介さず、UI要素間で直接プロパティ値の同期を取りたいことがある。このような場合に、ElementNameプロパティを指定することで、ほかのUI要素をバインディング・ソースにしてデータ・バインディングを行える。
例えば、List 8に示すようなXAMLコードを書くことで、テキストボックスに表示されるテキストと、スライダーの値を同期できる(スライダーのつまみを動かすと、即座にテキストが変化する)。
……省略……
<StackPanel>
<TextBox x:Name="textValue" />
<Slider Value="{Binding ElementName=textValue, Path=Text}" />
</StackPanel>
……省略……
○自分自身や先祖要素の参照
RelativeSourceプロパティを指定することで、UI要素自身や、先祖要素(=直接の親だけではなく、階層的にたどれる上位の要素すべて)のプロパティをデータ・ソースに指定することができる。利用例をList 9に示す。
……省略……
<StackPanel>
<!-- 先祖をたどって<Window>要素を見つけ、
そのTitleプロパティとバインディング -->
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window},
Path=Title}" />
<!-- 自分自身のWidthプロパティとHeightプロパティを
バインディング(要するに、正方形にする) -->
<Rectangle Fill="Blue" Width="50"
Height="{Binding RelativeSource={RelativeSource Self}, Path=Width}" />
</StackPanel>
……省略……
○値の変換
値そのままではなく、何らかの変換処理を行ってからデータ・バインディングしたい場合もあるだろう。そのような場合には、Bindingマークアップ拡張のConverterプロパティにIValueConverterインターフェイス(System.Windows.Data名前空間)を実装するクラスを渡す。
例えば、角度の度数(degree)と弧度数(radian:ラジアン)の(双方向)変換を考えてみよう。まず、List 10に示すように、IValueConverterインターフェイス実装クラスを用意する。
using System;
using System.Windows.Data;
using System.Globalization;
namespace atmarkit05
{
public class DegreeToRadianConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double x = (double)value;
return x / 180 * Math.PI;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
double x = double.Parse((string)value);
return (x / Math.PI * 180).ToString();
}
}
}
Public Class DegreeToRadianConverter
Implements IValueConverter
Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
Dim x As Double = CType(value, Double)
Return x / 180 * Math.PI
End Function
Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
Dim x As Double = Double.Parse(CType(value, String))
Return (x / Math.PI * 180).ToString()
End Function
End Class
このクラスを利用して、List 11に示すようなXAMLコードを記述することで、度と弧度の変換が可能になる。
……省略……
<StackPanel xmlns:local="clr-namespace:atmarkit05">
<StackPanel.Resources>
<local:DegreeToRadianConverter x:Key="DegToRad"/>
</StackPanel.Resources>
<Slider x:Name="slider" Value="0" Minimum="0" Maximum="360" />
<TextBox Text="{Binding ElementName=slider, Path=Value}" />
<TextBox Text="{Binding ElementName=slider, Path=Value,
Converter={StaticResource DegToRad}}" />
</StackPanel>
……省略……
○データ検証
Bindingマークアップ拡張では、エンド・ユーザーから入力されたデータの検証を行うために、以下の3つのプロパティを利用する。
データ検証の結果、何らかのエラーがあった場合には、Validation.HasError添付プロパティに「True」が設定され、Validation.Errors添付プロパティにエラーの一覧が格納される。
また、WPFのコントロールのいくつかは、標準でデータ検証エラーに対応していて、Figure 7に示すように、データ検証エラーがある場合にテキストボックスの枠線が赤くなるなどの変化が生じる(Validation.HasError添付プロパティをトリガーとしたスタイルが定義されている)。
IDataErrorInfoインターフェイスの実装方法については、次回で説明する。
続いて、データ・バインディングした単一のデータ/コレクション・データの表示方法をカスタマイズできる「データ・テンプレート」について説明する。
Copyright© Digital Advantage Corp. All Rights Reserved.