Last-modified: Sun, 14 Apr 2013 06:58:23 JST
Counter:2536 Today:1 Yesterday:0 Online:4
このエントリーをはてなブックマークに追加

Sample6 / より実用的な設計

About

このTemplateやStyleへの入門資料では、Buttonコントロールを例に解説をしています。サンプルではButtonのTemplateとして、BorderとTextBlockを定義していますが、WPFが提供する本来のButtonコントロールはContentプロパティを持っていて、例えば画像などをButtonの中に表示(設定)することができます。TextBlockではButtonが本来持つContentプロパティの役割を果たすことができません。

実のところ、ControlTemplateが提供するべきButtonコントロールの構成要素はTextBlockではなく、ContentPresenterと呼ばれる要素です。Sample6ではContentPresenterに置き換えて、Buttonの中に画像を表示する例を示します。

多くの資料がButtonを例として挙げているのは、トリガーやデザインの設定が最もシンプルに説明できるためだと思います。

HowTo

Sample5までと比較してControlTemplate内で変更された箇所はTextBlockがContentPresenterになった箇所だけです。実際にButton上に表示されるContentの内容は、テンプレートを利用するButton側で決定できるようにTemplateBindingを利用しています。

ソースコードとしてはButton側も変更されていますが、これについてはButtonコントロールの利用方法について解説する必要が出てくるので、ここでは解説を割愛します。StackPanelをButton.Controlに設定して、さらにそのStackPanelの中に画像とテキストを表示するように工夫してありますが、およそ一般的な利用方法の枠を漏れないでしょう。

    <UserControl.Resources>  
        <ControlTemplate TargetType="Button" x:Key="ButtonTemplate">    
            <Border Name="border"
                    Background="{TemplateBinding Background}"
                    CornerRadius="10"
                    Padding="10">
                <ContentPresenter Content="{TemplateBinding Content}" 
                                  VerticalAlignment="Top"
                                  HorizontalAlignment="Right"/>
            </Border>

            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter TargetName="border" Property="Background" Value="Blue" />
                </Trigger>
                <Trigger Property="IsMouseOver" Value="False">
                    <Setter TargetName="border" Property="Background" 
                            Value="{Binding Background, 
                            RelativeSource={RelativeSource TemplatedParent} }" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </UserControl.Resources>
    
    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">        
        <Button Height="50" Width="200" 
                Background="Green"
                Template="{StaticResource ButtonTemplate}">
            <StackPanel Orientation="Horizontal">
                <Image Source="Image/sampleimage.png" Stretch="UniformToFill" />
                <Label Content="Hello Template" Foreground="White"/>
            </StackPanel>
        </Button>
    </StackPanel>

これでSample6の内容は終わりです。さらにControlTemplateの具体的な解説も実質的には終わりで、Sample7からはStyleについて解説していきます。しかしながら、今後ControlTemplateの開発を行ったり、勉強を進める上で必要になる内容が残っています。以降の項目に掲載します。

Button以外のコントロールの構成要素

Buttonコントロールが本来持つ構成要素がContentPresenterであったことのように、他の様々なコントロールがどのような構成であるかを知らなければ、ControlTemplateの設計、外観のデザインは困難です。またTrigger(トリガー)についても同様で、どのようなイベント(トリガー)がコントロール上で検知されるのかを把握しなければ、やはり設計やデザインはできません。

私の調査不足もあるのかもしれませんが、公式にはmsdn(VisualStudio)にわずかに掲載されている情報しかないと思います。そしてこの資料を作るきっかけとなったように、それは非常にわかりにくい内容となっています(2013.04.14現在)。なぜ分かりにくいのかというと、対象のコントロールが正規に持っている構成要素のみを示した情報がないからです。

例えばここに示したページから"ボタンのスタイルとテンプレート"のページに移動すると、Buttonに設定することのできるTrigger(のイベント)の例になるであろう"表示状態の一覧"と、コントロールテンプレートを編集した例が掲載されています。このページの最終更新時点では、Triggerに設定できる正確な条件の一覧は掲載されていませんし、コントロールテンプレートの例も、複合的で分かりにくいものとなっています。

あるいは公式では次のページも役に立つかもしれません。ContentPresenterのように、ItemPresenterやTickBarといった、一般的なアプリケーション開発では触れることのない特殊な構成要素(コントロール)がどのコントロールであつかわれているかを確認することができます。

(2013.04.14)現在、コントロールの構成要素などを知るための最も良い方法は、"WPF Inspector"を利用することだと思われます。構成要素を閲覧するためのLogicalTreeの表示が可能であるため、ControlTemplateなどの開発に大いに利用することができるはずです。