連載:次世代技術につながるSilverlight入門

再利用性とUIのカスタマイズ

岩永 信之
2012/10/02
Page1 Page2 Page3 Page4

テンプレート

 スタイルでできる範囲、すなわち、単なるプロパティ値の設定では、例えばボタンの形状を丸ごと変化させるといった、大幅なカスタマイズはできない。

 ボタンであれば、もちろん、図形(System.Windows.Shapes名前空間以下の各種クラス。連載第3回参照)を使って所望の形状を作ったうえで、Clickイベントを使ってボタンに近い動作を実現する手立てもある。ただし、<Button>要素の場合、次回以降で説明するコマンド実行の仕組みも持っていて、この機能まで含めて再現するのはかなり骨の折れる作業となる。それに、スライダなどのように独自に実装するのが大変なコントロールもある。

 そこで「コントロール・テンプレート」という機能を使用する。コントロール・テンプレートは、Figure 10に示すように、コントロールの形状だけを丸ごと変化させつつ、コントロールの持つ機能(例えば、ボタンであればコマンド実行の仕組みなど)はそのまま利用できる仕組みである。

Figure 10: コントロール・テンプレートの適用

コントロール・テンプレートの適用

 コントロール(=Controlクラス(System.Windows.Controls名前空間)から派生する各種クラス)のTemplate属性によって、コントロール・テンプレートを適用する。直接適用するのであれば、例えばList 12に示すような書き方をする。

<Button Content="button 1" Width="60" Height="30">
  <Button.Template>
    <ControlTemplate>
      <Grid>
        <Ellipse Fill="LightBlue" Stroke="Blue" />
        <ContentPresenter
          Margin="5"
          HorizontalAlignment="Center"
          VerticalAlignment="Center" />
      </Grid>
    </ControlTemplate>
  </Button.Template>
</Button>
List 12: コントロール・テンプレートの直接適用

 スタイルと同様、List 13に示すように、リソース中で定義して、複数のコントロールから参照するという方法もある。

<StackPanel>
  <StackPanel.Resources>
    <ControlTemplate x:Key="ButtonTemplate">
      <Grid>
        <Ellipse Fill="LightBlue" Stroke="Blue" />
        <ContentPresenter
          Margin="5"
          HorizontalAlignment="Center"
          VerticalAlignment="Center" />
      </Grid>
    </ControlTemplate>
  </StackPanel.Resources>
  <Button
    Content="button 1" Width="60" Height="30"
    Template="{StaticResource ButtonTemplate}" />
  <Button
    Content="button 2" Width="60" Height="30"
    Template="{StaticResource ButtonTemplate}" />
</StackPanel>
List 13: リソースを使ったコントロール・テンプレートの定義と参照

 また、List 14に示すように、スタイルを使ってコントロール・テンプレートを適用する方法もよく使われる。

<StackPanel>
  <StackPanel.Resources>
    <Style TargetType="Button">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate>
            <Grid>
              <Ellipse Fill="{TemplateBinding Background}" />
              <ContentPresenter
                Margin="5"
                HorizontalAlignment="Center"
                VerticalAlignment="Center" />
            </Grid>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </StackPanel.Resources>
  <Button Content="button 1" Width="60" Height="30" Background="LightBlue" />
  <Button Content="button 2" Width="60" Height="30" Background="Pink" />
</StackPanel>
List 14: スタイルを使ってコントロール・テンプレートを適用
この場合、前述のスタイルの自動適用がかかって、全てのボタンにコントロール・テンプレートが適用される

テンプレート適用先のコントロールの属性値の参照

 List 14の例では、テンプレート適用先となるコントロールの属性値を参照するために、以下の2つのものを利用している。

  • <ContentPresenter>要素: この要素が置かれた位置に、コントロールのコンテンツ(=Contentプロパティに与えた値)が配置される。
  • TemplateBindingマークアップ拡張:コントロールに与えられたプロパティ値を取得するために利用する。

 これらによって、2つあるボタンのContent属性とBackground属性の値が反映され、Figure 11のような結果が得られる。

Figure 11: List 14のXAMLコードの結果

補足: VisualStateManager

 ボタンをはじめとするほとんどのコントロールは、マウス・オーバーやクリックなど、ユーザー操作状態によって視覚的な状態(visual state)が変化する(List 12〜List 14のテンプレート例では、簡単化のため、このような変化には対応していない)。

 このような視覚的な状態の管理のために、SilverlightはVisualStateManagerというクラス(System.Windows名前空間)を提供している(VisualStateManager自体の説明は、次回以降、アニメーションの回に行う予定である)。

 Visual Studio 2012には、Figure 12に示すように、デフォルトのものをコピーして新しいコントロール・テンプレートを作成する機能が備わっている。この機能を使ってデフォルトのコントロール・テンプレートの内容をのぞけば、VisualStateManagerの利用方法を見て取れるだろう。

Figure 12: Visual Studio 2012を使ったテンプレートの作成

 生成されるコピーは非常に長くなるため一部抜粋にとどめるが、例えばボタンであれば、List 15に示すようなものになる。

<ControlTemplate TargetType="Button">
  <Grid>
    <VisualStateManager.VisualStateGroups>
      <VisualStateGroup x:Name="CommonStates">
        <VisualState x:Name="Normal"/>
        <VisualState x:Name="MouseOver">
          <Storyboard>
            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundAnimation"/>
            <ColorAnimation Duration="0" To="#F2FFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
            <ColorAnimation Duration="0" To="#CCFFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
            <ColorAnimation Duration="0" To="#7FFFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
          </Storyboard>
        </VisualState>
……後略……
List 15: ボタンのコントロール・テンプレート(一部抜粋)

 ちなみに、Visual Studioはこの視覚的な状態管理や、アニメーション関連の編集機能は貧弱で、これらの編集にはBlendの利用を推奨する。Visual Studio 2012で、Visual StudioとBlendのXAMLエディタ/ビジュアル・デザイナがかなり共通化されたものの、アニメーションなどの機能は未だにBlendのみである。

 デスクトップ・アプリ向けやSilverlight向けのBlendは有償ツールだが、Windows 8のWindowsストア・アプリ向けのものや、Windows Phone向けのものは無償でSDKやVisual Studio Expressに付属している。

 最後に次のページで、独自コントロールの作成方法について説明する。


 INDEX
  [連載] 次世代技術につながるSilverlight入門
  再利用性とUIのカスタマイズ
    1.リソース
    2.スタイル
  3.テンプレート
    4.コントロールの作成

インデックス・ページヘ  「連載:次世代技術につながるSilverlight入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH