【WinRT】カスタムコントロールをつかったピボットコントロールの実装


10月18日からWindows ストアにてWindows 8.1の無償提供が開始されます。
検索チャームやスナップの仕様が変更されている点など、正式リリース後公開アプリに変更が必要な点も存在します。
使いやすくなっている点も多く正式リリースが楽しみです。

これまでにも、カスタムコントロールを使った「アプリバーボタンの実装方法」や「セマンティックズームの実装」ったについてご紹介しましたが、今回は「ピボットコントロール」をカスタムコントロールで作成する方法をご紹介します。

Windowsストアアプリにもよく使用される、ページ内で表示内容を切り替えるためのコントロールの1つです。
「メニュー切り替えが容易なこと」「メニューが一目で把握できること」など、ユーザにとってわかりやすいコントロールです。
プルダウンメニューに比べて、切り替えの使用頻度が高くメニューが少ない場合に活用するとよいと思います。

しかし、残念ながらWinRTの標準にはピボットコントロールが用意されていません。
一度カスタムコントロールを作っておくと便利だと思います。

 

Windows ストア アプリにおけるピボットコントロール

【 一般的なタブメニューとの違い 】

Windows ストア アプリのピボットコントロールは、普段よく見かけるタブと見た目の仕様が違うことにお気づきでしょうか。
デザインにも依存しますが、ピボットコントロールは選択されているメニューが、ColorやFontWeight等で強調されるのが一般的です。また他のメニューは、Colorがグレーでになっているものが多いです。
他の一般的なタブメニューを考えると、選択されているメニューのColorが「グレー」になっていて、その他のメニューがColor等で強調されているUIが多いです。

【 デザインについて 】

ピボットコントロールには、シンプルなラベルのみのデザインもありますが、必要に応じてアイコンやメニューに該当するコンテンツの数を表示させることも効果的です。

【 フィルター機能としての使用】

ピボットコントロールには、表示メニューの切り替えの他にフィルター機能として使用できるという特徴があります。
フィルターメニューとして使用する場合は、一般的に一番左側に「すべて(英語表記ではAll)」を配置します。
コンテンツの数を表示すると親切でわかりやすいです。
フィルター機能として使用する場合も、フィルターメニューの切り替え頻度が高いときに使用します。そのほかの場合には、アプリバーのポップアップメニューやアプリバーに複数のフィルターコマンドを設けるとよいです。

ピボットコントロールをつくってみる

【 CustomPivotControl.cs 】

ピボットコントロールを作成する場合は、「RadioButton」を継承したカスタムコントロールをつくります。
DefaultStyleKey を設定して、「Themes/Generic.xaml」というリソースディクショナリーにスタイルを定義することで、プラットフォームが自動的にスタイルを参照してくれます。

public class CustomPivotControl:RadioButton
   {
      public CustomPivotControl()
      {
         this.DefaultStyleKey = typeof(CustomPivotControl);

      }
      :
      :
}

アイコンをつけたいときには以下のプロパティをつくります。バインドするプロパティは依存関係プロパティを使います。
非選択時用の画像も同様に作ります。アイコンの画像サイズを可変にしたい場合はサイズプロパティも用意しましょう。

//選択用画像 
public ImageSource Image
{
   get { return (ImageSource)GetValue(ImageProperty); }
   set { SetValue(ImageProperty, value); }
}
//選択用画像 – 依存関係プロパティ 
public static readonly DependencyProperty ImageProperty =
DependencyProperty.Register(“Image”, typeof(ImageSource), typeof(CustomPivotControl), new PropertyMetadata(null));

数字をつけたいときにはCountプロパティをつくります。

//カウント 
public int Count
{
   get { return (int)GetValue(CountProperty); }
   set { SetValue(CountProperty, value); }
}
//カウント – 依存関係プロパティ 
public static readonly DependencyProperty CountProperty =
DependencyProperty.Register(“Count”, typeof(int), typeof(CustomPivotControl), new PropertyMetadata(null));

【 Themes/Generic.xaml 】

自分で用意したプロパティに対して初期値を設けたいときには下記のように設定しておきます。

<Style TargetType=”local:CustomPivotControl”>
 <Setter Property=”Height” Value=”40″/>
 <Setter Property=”VerticalAlignment” Value=”Bottom”/>
 <!– 自分でつくったプロパティに初期値を持たせたい場合にはここで指定する –>
 <Setter Property=”ImageSize” Value=”30″/>
 <Setter Property=”Count” Value=”0″/>

 <Setter Property=”Template”>
  <Setter.Value>
   <ControlTemplate TargetType=”local:CustomPivotControl”>
    <!– ①ピボットコントロールのレイアウトを後述 –>
   </ControlTemplate>
  </Setter.Value>
 </Setter>
</Style>

【 ①ピボットコントロールのレイアウト 】

プロパティの値のバインドには「TemplateBinding」を使用します。
自分で作成したプロパティもRadioButtonのプロパティを利用する場合も同様です。下記ではContentプロパティやFontSizeプロパティをラベルや数字用に使用しています。
Converterを使用したいときには以下のように指定します。

{Binding プロパティ名, RelativeSource={RelativeSource TemplatedParent},
   Converter={StaticResource コンバーター名}}”

また下記の例では、数字(Count)が「0」の場合、アイコン画像が存在しないときに非表示になるようにVisibilityにConverterを設定しています。Converterについては省略しますが、必要に応じて作成すると便利です。

<Grid Background=”Transparent”>
 <!– ②ビジュアルステートについて後述–>
 <StackPanel Orientation=”Horizontal” >
 <!– アイコン画像–>
 <Image x:Name=”Image
  Visibility=”{Binding Image, RelativeSource={RelativeSource TemplatedParent},
   Converter={StaticResource NullToCollapsedConverter}
}”
  Height=”{TemplateBinding ImageSize}”
  Width=”{TemplateBinding ImageSize}”
  Margin=”0,0,5,0″ VerticalAlignment=”Center”/>
 <!– ラベル–>
 <TextBlock x:Name=”Text
  Text=”{TemplateBinding Content}”
  FontSize=”{TemplateBinding FontSize}”
  Margin=”0″ TextWrapping=”NoWrap” VerticalAlignment=”Center” />
 <!– 数字(括弧付き)–>
 <StackPanel Orientation=”Horizontal” Margin=”4,0,0,0″
  Visibility=”{Binding Count,RelativeSource={RelativeSource TemplatedParent},
   Converter={StaticResource IntegerToCollapsedConverter}
}”>
    <!– Mark1:(–>
    <TextBlock x:Name=”Mark1
     Text=”(” Margin=”0″ TextWrapping=”NoWrap” VerticalAlignment=”Center”
     FontSize=”{TemplateBinding FontSize}”/>
    <!– Count:数字–>
    <TextBlock x:Name=”Count
     Text=”{Binding Count,RelativeSource={RelativeSource TemplatedParent},
      Converter={StaticResource IntegerToStringConverter}
}”
     FontSize=”{TemplateBinding FontSize}”
     Margin=”0″ TextWrapping=”NoWrap” VerticalAlignment=”Center”/>
    <!– Mark2:)–>
    <TextBlock x:Name=”Mark2
     Text=”)” Margin=”0″ TextWrapping=”NoWrap” VerticalAlignment=”Center”
     FontSize=”{TemplateBinding FontSize}”/>
 </StackPanel>
 </StackPanel>
<!– (省略)Tab移動用のFocusVisualなど–>
</Grid>

【 ②ビジュアルステートについて】

ピボットコントロールでは、マウスオーバー時と選択時、非選択時の状態を決めておきます。
ビジュアルステートの設定でプロパティの値を変化させるときには、下記のように設定することに注意してください。

{Binding プロパティ名, RelativeSource={RelativeSource TemplatedParent}}

下記の例では以下のように設定しています。

・マウスオーバー時にOpacityが変化する
・選択時にはアイコン画像とカラーが変化、フォントを太字にする
・非選択時にはアイコン画像とカラーが変化、フォントを通常の太さにする

<VisualStateManager.VisualStateGroups>
 <VisualStateGroup x:Name=”CommonStates”>
  :
  :
 <!– マウスオーバー時:PointerOver–>
  <VisualState x:Name=”PointerOver”>
   <Storyboard>
    <!– アイコン画像:Image –>
    <ObjectAnimationUsingKeyFrames Storyboard.TargetName=”Image”                     
        Storyboard.TargetProperty=”Image.Opacity”>
      <DiscreteObjectKeyFrame KeyTime=”0″ Value=”0.7″/>
    </ObjectAnimationUsingKeyFrames>
    :
    <!– (省略)ラベル:Text 数字:Count Mark1 Mark2も同様 –>
    :
   </Storyboard>
  </VisualState>
 </VisualStateGroup>
 <VisualStateGroup x:Name=”CheckStates”>
 <!– 選択時:Checked–>
  <VisualState x:Name=”PointerOver”>
   <Storyboard>
    <!– アイコン画像:Image –>
    <ObjectAnimationUsingKeyFrames Storyboard.TargetName=”Image”               
        Storyboard.TargetProperty=”Image.Source”>
      <DiscreteObjectKeyFrame KeyTime=”0″
    Value=”{Binding Image, RelativeSource={RelativeSource TemplatedParent}}”/>
    </ObjectAnimationUsingKeyFrames>
    <!– ラベル:Text –>
    <ObjectAnimationUsingKeyFrames Storyboard.TargetName=”Text”                
        Storyboard.TargetProperty=”TextBlock.FontWeight”>
      <DiscreteObjectKeyFrame KeyTime=”0″ Value=”Bold”/>
    </ObjectAnimationUsingKeyFrames>
    <ObjectAnimationUsingKeyFrames Storyboard.TargetName=”Text”                
        Storyboard.TargetProperty=”TextBlock.Foreground”>
      <DiscreteObjectKeyFrame KeyTime=”0″ Value=”選択用のカラーブラシ”/>
    </ObjectAnimationUsingKeyFrames>
    :
    <!– (省略)数字:Count Mark1 Mark2も同様 –>
    :
   </Storyboard>
  </VisualState>

 <!– 非選択時:UnChecked–>
  <VisualState x:Name=”Unchecked”>
   <Storyboard>
    <!– アイコン画像:Image –>
    <ObjectAnimationUsingKeyFrames Storyboard.TargetName=”Image”               
        Storyboard.TargetProperty=”Image.Source”>
      <DiscreteObjectKeyFrame KeyTime=”0″
   Value=”{Binding UncheckedImage, RelativeSource={RelativeSource TemplatedParent}}”/>
    </ObjectAnimationUsingKeyFrames>
    <!– ラベル:Text –>
    <ObjectAnimationUsingKeyFrames Storyboard.TargetName=”Text”                
        Storyboard.TargetProperty=”TextBlock.Foreground”>
      <DiscreteObjectKeyFrame KeyTime=”0″ Value=”非選択用のカラーブラシ”/>
    </ObjectAnimationUsingKeyFrames>
    :
    <!– (省略)数字:Count Mark1 Mark2も同様 –>
    :
   </Storyboard>
  </VisualState>
  :
  :
 </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

ピボットコントロールをつかってみる

使うときはスタイルで定義すると便利です。

<Style x:Key=”PivotRadioButtonStyle1″ TargetType=”local:CustomPivotControl” >
  <Setter Property=”Image” Value=”ms-appx:///Assets/checked.png”/>
  <Setter Property=”UncheckedImage” Value=”ms-appx:///Assets/unchecked.png”/>
  <Setter Property=”FontSize” Value=”20″/>
  <Setter Property=”Content” Value=”連絡先”/>
</Style>

数字(カウント)などは使用するときにXAMLやC#でセットします。

<local:CustomPivotControl GroupName=”SearchTab”
    Style=”{StaticResource PivotRadioButtonStyle1}” IsChecked=”True” Count=”15″ />
<local:CustomPivotControl GroupName=”SearchTab”
    Style=”{StaticResource PivotRadioButtonStyle2}” IsChecked=”False” Count=”2″ />
<local:CustomPivotControl GroupName=”SearchTab”
    Style=”{StaticResource PivotRadioButtonStyle3}” IsChecked=”False” Count=”4″ />

まとめ

表示内容の切り替えに使用するコントロールには、「ピボットコントロール」のほかにも「プルダウンメニュー」、フィルター機能には「アプリバーのポップアップメニュー」や「アプリバーの複数コマンド」などがあります。アプリによっては、ヘッダーの右上部分に表示切替用のコマンドを設けている場合もあります。

前述の通りピボットコントロールのメリットは、「メニュー切り替えが容易なこと」「メニューが一目で把握できること」などです。他のコントロールに比べて、ページ内に広い範囲を確保する必要がありますので、使用頻度がそれほど高くないメニューには使用しないほうが望ましいです。

Windows ストア アプリに広く活用できる部品なので、是非カスタムコントロールで作成しておいてはいかがでしょうか。