Last-modified: Sat, 23 Mar 2013 19:20:17 JST
Counter:2640 Today:1 Yesterday:2 Online:5
このエントリーをはてなブックマークに追加

Sample5 / トリガーと可変デザイン

About

Sample4では "特定の条件下にあるUIのデザインを設定するための仕組み" トリガーについて解説しました。ここでSample3も思い出してみます。Sample3では、Template中の特定のデザインをButtonに定義されたプロパティから設定できるようにしていました。例えばBackgroundプロパティです。Template中のBackgroundプロパティのみ、ButtonのプロパティBackgroundから設定できるようにしました。

ここでSample4であつかったトリガー(Trigger)とそのデザインの変更を定義するSetterに注目します。例えば、ボタン(Button)上にマウスがある場合にはButton.Backgroundに設定した背景になるように、マウスが上にない場合には黒になるように設計するとします。Sample3を例に見れば、次のコードのように設定しようとするでしょう。

<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value ="{TemplateBinding Background}" />
…

ところがSetter中に、TemplateBindingは利用することができません。そこでこのSample5では、この問題を解決し、トリガー(Trigger)中でButtonに設定されるプロパティの値を利用する方法について解説します。サンプルではSample4からの変化が分かりやすいように、ボタンの色を緑(Green)に変更しています。

HowTo

Sample4から変更された箇所は1か所だけです。変更箇所は"IsMouseOver Value=Flase"となるTriggerに定義されたSetterです。Setterに設定されるValueの値が複雑になっていることを確認してください。該当箇所だけ取り出すと次のようになっています。Sample5で解説する内容はこれだけです。

Value = "{Binding Background, RelativeSource={RelativeSource TemplatedParent}}"

これはWPF全般で利用されるBindingの機能をTemplateに当てはめたようなもので、そもそもBindingの概念が分かりにくいので、もしもBindingについて理解できないのであれば、こう書くものだと覚えてしまうのが良いでしょう。Bindingについて解説すると、目的からズレていくので、ここでは記述だけ頭から順に追っていきます。

  1. Binding Background
    • Binding対象はBackground(プロパティ)であり、
  2. RelativeSource =
    • その(Backgroundの)値を提供するのは次の相対的な対象である。
      • ここでの相対的とは"参照できるソースコード中に必ず存在するわけではない"で良いです。
  3. RelativeSource TemplatedParent
    • このTemplateを利用する親要素(ここではButton)を相対的な要素とする。
    <UserControl.Resources> 
        <ControlTemplate TargetType="Button" x:Key="ButtonTemplate">      
            <Border Name="border"
                    Background="{TemplateBinding Background}"
                    CornerRadius="10"
                    Padding="10">
                <TextBlock Text="Hello Template"
                           Foreground="White"
                           VerticalAlignment="Center"
                           HorizontalAlignment="Left"/>
            </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 ="{TemplateBinding Background}" />-->
                    <Setter TargetName="border" Property="Background" 
                            Value="{Binding Background, 
              RelativeSource={RelativeSource TemplatedParent}}" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>  
    </UserControl.Resources>
  
    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">        
        <Button Content="Button" Height="50" Width="200" 
                Background="Green"
                Template="{StaticResource ButtonTemplate}" />
    </StackPanel>

RelativeSourceがすこぶる分かりにくいのですが、そもそもRelativeSourceにあまり触れていない場合には、公式(msdn)の文章だけを読んでも分からないと思います。

Sample5はこれで終わりです。ここではBackgroundプロパティを対象にしていますが、Foregroundなどを対象に利用することもできるでしょう。