投稿数 - 388, コメント - 2169, トラックバック - 138

XAML の子要素の扱い

手続き型言語にどっぷり浸かっているせいか、宣言型の言語というものはどうもわかりにくい。SQL 然り、XAML 然り。先ず、XAML でわかりにくいと思ったのは「子要素の扱い」だ。

Code 1
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test" Height="200" Width="200" >
    Hello World
</Window>

Code 2
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test" Height="200" Width="200" >
    <Button>Hello</Button>
    <Button>World</Button>
</Window>

Code 1 は、Window に "Hello World" と表示しているだけ。Code 2 はコンパイルエラーになる。Window が持てる子要素は 1 つだけなのだ。次は、Window に Grid を持たせ、Button を 2 つ配置した。

Code 3
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test" Height="200" Width="200" >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Button Grid.Row="0">Hello</Button>
        <Button Grid.Row="1">World</Button>
    </Grid>
</Window>

Gird にはいくつでも子要素を持たせることができる。

Window に子要素を設定すると Window.Content に設定され、Grid に子要素を設定すると Grid.RowDefinitions の 1 要素となる(※1)。この様に、子要素は親要素の「どれに設定される」のか決まっていないが、XAML コンパイラはそれをどうやって判断しているのだろうか?

XAML コンパイラは子要素の取り扱いを親要素に一任している。その際に肝となるのが IAddChild インターフェースだ。IAddChild インターフェースを持っているクラスは子要素を持つことができ、IAddChild インターフェースを実装してさえいれば、親要素は子要素を好きなように扱える。Window の場合は、AddChild メソッドに渡された Object を Content に設定しているのだろう。

この事実を知っていると XAML の構造がすっきりと理解できる。

また、XAML はコレクションのようなものも扱えるので(※2)、ICollection インターフェースを実装しているクラスも子要素を持てるみたいだ。

 

※1 厳密には、Grid.RowDifinitions の要素となるのは RowDifinition のインスタンス。

※2 XAML は UI 専用言語ではない

投稿日時 : 2007年5月20日 0:33

フィードバック

# re: XAML の子要素の扱い

Window が持てる子要素は1つだけ、2つ以上持たせたらコンパイルエラーってのは、コンパイラは何を根拠に判断してるんだろうか? スキーマ? それとも、試しに AddChild してみるとか?
さて、Window の派生クラスをユーザが作ったりしたら、この制限は継承されるのか、書き換えられるのか? AddChild の実装は変えられるはずだものね。
2007/05/20 19:40 | シャノン@XAML知らず

# re: XAML の子要素の扱い

さすがいいところに目を着けますね。
試しに AddChild してるんだろうなぁと予想していますが。
2007/05/21 20:23 | 囚人

# re: XAML の子要素の扱い

WPFでの 「Contentモデル」 を表現する中で,
概念としての 「コンテント・プロパティ」 は,
ContentProperty属性 が付いているものが
概念としての 「コンテント・プロパティ」 になってます。

ContentControlから継承されたものは,
そのまんま Contentプロパティという名前のものがそれになっています。
Window などはそれです。

[ContentPropertyAttribute("Content")]
public class ContentControl : Control, IAddChild


でも,
継承ツリーで先に枝分かれしてしまっているPanel系のものは,
そもそも Contentプロパティ という実際のプロパティ名はなく,
概念としての 「コンテント・プロパティ」 は,
Childrenプロパティ というものに対して属性が付いてます。

[ContentPropertyAttribute("Children")]
public abstract class Panel : FrameworkElement, IAddChild


ItemsControl では,
Items が 概念として「コンテント・プロパティ」 になっていたりとか,

[ContentPropertyAttribute("Items")]
public class ItemsControl : Control, IAddChild

コンテントモデルの種類が 6パターンあるので,
ContentPropertyAttribute で指定されたプロパティが
コレクションかどうかで判断しているような気がします。
でも,気がするってレベルですが。
2007/05/22 0:31 | 稍丼

# re: XAML の子要素の扱い

> 6パターンあるので

6パターンあるのを,それぞれ調べてみると,
2007/05/22 1:10 | 稍丼

# re: XAML の子要素の扱い

ContentPropertyAttribute の Remarks のところに

In order to accept more than a single object element as content, the type of the content property must be a collection type.

とあるので,コレクションかどうかで判断してるっぽいですね。
2007/05/22 1:32 | 稍丼

# re: XAML の子要素の扱い

>ContentPropertyAttribute

なるほど。属性があったんですね。それとコレクションか。
ありがとうございます!
2007/05/22 18:47 | 囚人

コメントの投稿

タイトル  
名前  
URL
コメント