「Androidは電気羊の夢を見るか」を読みたい管理者のブログ

仕事などでの色々な発見を記事にしてます。不定期更新。

ContentControlのDataTemplateネタが少なくて少しさびしい

ご無沙汰しております。ここは本来技術ネタを書く場所だったんですが、方向がずれてきてまた技術に返り咲こうかなと。
昔の記事を見てると色々やってるもんですね。ボタンを動的に配置したい、トリガーでStyleを変更したい、アニメーション云々。
久しぶりにWPFに戻ってまいりました。
昔に比べてDataTemplateの記載は増えた気がする。現場では当たり前のように使われるDataTemplate。動的配置だいだいだいすき。
でも気になることがあるんですよね。DataTemplateの記事を見てるとItemsControl(ListBoxでもいいが)の記載ばかり目に入る。
そうじゃないんだ、DataTemplateはContentPresenterでも使える重要な要素なんだ、というのをね。もっと強調してもいいのかな、と思いこの記事を書きます。


参考
atmarkit.itmedia.co.jp
grabacr.net
livealoneblog.com

今回紹介するのはDataTemplateのリスト型じゃない使い方です。
まず、リソースでDataTemplateを定義してあげます。

<Window.Resources>
        <DataTemplate DataType="{x:Type local:Cat}">
            <Border BorderBrush="Gold" BorderThickness="2" Background="AntiqueWhite">
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="{Binding Kind}"/>
                    <TextBlock Text="{Binding Age, StringFormat={}{0:N0}歳}"/>
                </StackPanel>
            </Border>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:PetCat}">
            <Border BorderBrush="Black" BorderThickness="2" Background="WhiteSmoke">
                <StackPanel Orientation="Horizontal" Margin="4">
                    <Image Source="{Binding Face}" Width="32" Height="32"/>
                    <TextBlock Foreground="DeepSkyBlue"
                                       FontSize="20"
                                       Text="{Binding Kind}"
                                       TextAlignment="Center"/>
                </StackPanel>
            </Border>

        </DataTemplate>
</Window.Resources>

丸パクリですがモデルを用意してあげましょう。

    public class Cat
    {
        public string Kind { get; set; }
        public int Age { get; set; }

        public override string ToString()
        {
            return string.Format("{0} {1}歳", Kind, Age);
        }
    } 
   public class PetCat : Cat
    {
        public Uri Face { get; set; }
    }

ViewModel内にプロパティを配置

        public Cat NormalCat
        {
            get {
                return new Cat
                {
                    Age = 10,
                    Kind = "黒猫"
                };
             }
        }
        public PetCat PetCat
        {
            get
            {
                return new PetCat() { Kind = "アメリカン・ショートヘア", Age = 4, Face = new Uri("test.png", UriKind.Relative) };
            }
        }

XAMLを記述。たったこれだけです。

        <ContentControl Grid.Row="5" Content="{Binding NormalCat, ElementName=mine}"/>
        <ContentControl Grid.Row="6" Content="{Binding PetCat, ElementName=mine}"/>

これだけで済むのはDataContextにDataTypeを指定してあげてるから
実行結果

このようにDataTypeによって別々のDataTemplateが指定されているのがわかります。

これだけだとなんなんで公式を見てみると
docs.microsoft.com
長い継承関係の末にContentControlで初めてDataTemplate型プロパティが付与されるんですね。

DataTemplateはコントロールの動的生成に用いられがちだけど単独でも使用できるよという話でした。