前回は、XAML の要素、属性、型変換について見ました。
XAML では、要素が .NET のオブジェクトを表し、属性がプロパティへの値設定を表します。
<Button Content="保存"
Width="120" />
このような属性構文は短く書けて便利です。しかし、設定したい値が複雑になると、属性だけでは表しにくくなります。
そこで使うのが、プロパティ要素構文です。
属性構文の限界
まず、単純な値であれば属性構文で十分です。
<TextBlock Text="こんにちは"
FontSize="20" />
これは、TextBlock の Text プロパティと FontSize プロパティを設定しています。
しかし、プロパティに設定したい値が別のオブジェクトである場合は、属性だけでは書きにくくなります。
たとえば、ボタンの内容に単なる文字列ではなく、複数の要素を入れたい場合を考えます。
<Button>
<StackPanel Orientation="Horizontal">
<TextBlock Text="保存" />
</StackPanel>
</Button>
この例では、ボタンの中に StackPanel を入れ、その中に TextBlock を置いています。
これは短く書かれていますが、実際には Button の Content プロパティに StackPanel を設定しています。
プロパティ要素構文の基本
同じことを、プロパティ名を明示して書くと次のようになります。
<Button>
<Button.Content>
<StackPanel Orientation="Horizontal">
<TextBlock Text="保存" />
</StackPanel>
</Button.Content>
</Button>
これがプロパティ要素構文です。
Button.Content は、新しいオブジェクトを作っているのではありません。Button の Content プロパティに値を設定するための記述です。
形式は次のようになります。
<型名.プロパティ名>
プロパティに設定する値
</型名.プロパティ名>
つまり、次のように読めます。
Button を作る。
その Content プロパティに、内側の StackPanel を設定する。
属性構文と同じ意味になる場合
属性構文とプロパティ要素構文は、同じプロパティを設定する別の書き方です。
たとえば、次の XAML は属性構文です。
<Button Content="保存" />
これをプロパティ要素構文で書くと、次のようになります。
<Button>
<Button.Content>
保存
</Button.Content>
</Button>
どちらも Content プロパティに値を設定しています。
ただし、単純な文字列であれば属性構文のほうが読みやすいです。プロパティ要素構文は、属性では書きにくい複雑な値に使う、と考えるとよいでしょう。
複雑なオブジェクトを設定する
プロパティ要素構文は、ブラシやテンプレートなどの複雑なオブジェクトを設定するときによく使います。
たとえば、単色の背景であれば属性で書けます。
<Border Background="LightBlue" />
しかし、グラデーションを使いたい場合は、複数の要素を組み合わせる必要があります。
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0,0"
EndPoint="1,1">
<GradientStop Color="LightBlue"
Offset="0" />
<GradientStop Color="SteelBlue"
Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
この例では、Border.Background プロパティに LinearGradientBrush を設定しています。
属性構文では表しにくい複雑な値を、要素として展開して書けるのがプロパティ要素構文の強みです。
コレクションを設定する
プロパティ要素構文は、コレクションを設定するときにもよく使います。
たとえば、Grid の行定義は次のように書きます。
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="見出し" />
<TextBox Grid.Row="1" />
</Grid>
Grid.RowDefinitions は、Grid の行定義コレクションを表すプロパティです。
その中に RowDefinition を複数入れることで、行の構成を定義しています。
同じように、列定義は Grid.ColumnDefinitions に書きます。
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
このように、プロパティの値がコレクションである場合、内側に複数の要素を並べて書けます。
コンテンツプロパティによる省略
WPF の XAML では、よく使うプロパティを省略して書ける場合があります。
たとえば、Button は Content プロパティを持つため、次のように書けます。
<Button>
<TextBlock Text="保存" />
</Button>
これは、明示的に書くと次の意味です。
<Button>
<Button.Content>
<TextBlock Text="保存" />
</Button.Content>
</Button>
このように、要素の内側に直接書いた内容が、特定のプロパティに入ることがあります。その特定のプロパティを、コンテンツプロパティと呼びます。
StackPanel の場合は、内側の要素が子要素コレクションに入ります。
<StackPanel>
<TextBlock Text="名前" />
<TextBox />
</StackPanel>
これは、StackPanel の子要素として TextBlock と TextBox を追加していると考えられます。
読み方のコツ
プロパティ要素構文を読むときは、点の前後に注目します。
<Border.Background>
これは、Border の Background プロパティです。
<Grid.RowDefinitions>
これは、Grid の RowDefinitions プロパティです。
点が入っている要素を見たら、新しい画面部品ではなく、プロパティへの値設定だと考えます。
ただし、次回扱う添付プロパティにも点が入ります。プロパティ要素構文と添付プロパティは形が似ているため、最初は混乱しやすいところです。
まずは、次の区別を押さえておきます。
| 構文 | 例 | 読み方 |
|---|---|---|
| プロパティ要素構文 | <Button.Content> | Button の Content プロパティを要素として書く |
| 添付プロパティ | Grid.Row="1" | Grid が管理する Row 情報を別の要素に付ける |
まとめ
プロパティ要素構文は、属性では書きにくい値を設定するための構文です。
| 書き方 | 向いている値 |
|---|---|
| 属性構文 | 文字列、数値、列挙値、簡単な色や余白 |
| プロパティ要素構文 | 複雑なオブジェクト、コレクション、複数の子要素 |
XAML を読むときは、次の視点が役に立ちます。
要素はオブジェクトを作る。
属性はプロパティを設定する。型名.プロパティ名 の要素は、そのプロパティに複雑な値を設定する。
次回は、WPF のレイアウトで頻繁に登場する添付プロパティについて整理します。