GridView/ListViewのアイテムの外観を変えるには?(その2)[Win 8]WinRT/Metro TIPS

データ・テンプレートやアイテム・コンテナ・スタイルを動的に切り替える「セレクタ」を使ってGridView/ListViewコントロールの外観を大きく変化させる方法を説明する。

» 2013年03月14日 14時48分 公開
[山本康彦BluewaterSoft]
WinRT/Metro TIPS
業務アプリInsider/Insider.NET

powered by Insider.NET

「WinRT/Metro TIPS」のインデックス

連載目次

 データの一覧をグループごとに分けて表示するときによく使うのが、GridViewコントロールとListViewコントロールだ。その外観を変える方法として、前回はデータ・バインドを応用する方法を説明したが、外観にもっと大胆な変化を付けることはできないだろうか? 例えば、よく見かける、グリッドに大小のセルが混在したデザインはどのようにして実現しているのだろうか?

 このような場合に便利に使えるのが、データ・テンプレートやアイテム・コンテナ・スタイルを動的に切り替える「セレクタ」だ。そこで本稿では、セレクタを使ってGridViewコントロールの外観に変化を付ける方法を説明する。本稿のサンプルは「Windows Store app samples:MetroTips #28」からダウンロードできる。

事前準備

 Windows 8(以降、Win 8)向けのWindowsストア・アプリを開発するには、Win 8とVisual Studio 2012(以降、VS 2012)が必要である。これらを準備するには、第1回のTIPSを参考にしてほしい。本稿では64bit版Win 8 ProとVS 2012 Express for Windows 8を使用している。

データ・テンプレートを切り替えるには?

 複数のデータ・テンプレートを用意しておき、DataTemplateSelectorクラス(Windows.UI.Xaml.Controls名前空間)を継承して作ったセレクタで切り替える。

 前回と同様にVS 2012の「グリッド・アプリケーション」プロジェクト・テンプレートから始めよう。グリッド・アプリケーションの起動時には、GroupedItemsPage.xamlファイルで定義される画面が表示される。この画面では、GridViewコントロールを使ってアイテムが表示されるが、そのときにはGridViewコントロールのItemTemplateプロパティに設定されているデータ・テンプレートが使われる。そして、このデータ・テンプレートはデフォルトでは「Standard250x250ItemTemplate」となっている*1。これを次の画像のように別のデータ・テンプレートと動的に切り替えられるようにしてみよう。

*1 Standard250x250ItemTemplateは、プロジェクトのCommonフォルダのStandardStyles.xamlファイルに記述されている。


各グループの先頭のアイテムだけに別のデータ・テンプレートを適用した画面 各グループの先頭のアイテムだけに別のデータ・テンプレートを適用した画面
グレーのタイルには元のStandard250x250ItemTemplateが適用されている。赤いタイルにはこの後で作成するデータ・テンプレートが適用されている。この2つのテンプレートを、セレクタを使い、表示するデータに応じて動的に切り替えることで外観に変化を付けている。

 まず、新しいデータ・テンプレートを「App.xaml」ファイルのResourceDictionary要素の中に追加する。名前は「itemGridView2ndItemTemplate」としておこう(次のコード)。

<!-- itemGridViewの最初のアイテムに適用するテンプレート -->
<DataTemplate x:Key="itemGridView2ndItemTemplate">
  <Grid Background="DarkRed" Width="250" Height="250">
    <TextBlock Text="{Binding Title}" Foreground="White"
               FontSize="36" HorizontalAlignment="Center"
               VerticalAlignment="Center" />
  </Grid>
</DataTemplate>

追加するデータ・テンプレート(XAML)
テンプレートの内容は簡略化してある。赤色の背景に白文字で大きくタイトルを表示するだけのものである。

 次に、上述の2つのテンプレートを動的に切り替えるためのクラスを新しく追加する。クラス名は「ItemGridViewTemplateSelector」としよう。DataTemplateSelectorクラスを継承させ、SelectTemplateCoreメソッドを次のようにオーバーライドする。

 このメソッドには表示しようとしているデータが引数として渡されるので、メソッドの側では受け取ったデータを調べてそれに見合ったテンプレートを返してやればよいのだ。ここでは、表示するデータ(=プロジェクト・テンプレートに含まれるSampleDataItemクラスのオブジェクト)のUniqueIdプロパティに「Item-1」という文字列が含まれているときに、新しく作ったテンプレートが使われるようにした。

class ItemGridViewTemplateSelector : DataTemplateSelector
{
  protected override DataTemplate SelectTemplateCore(
      object item, DependencyObject container)
  {
    var data = item as SampleDataItem;
    if (data.UniqueId.Contains("Item-1"))
    {
      return (DataTemplate)App.Current.Resources["itemGridView2ndItemTemplate"];
    }
    return (DataTemplate)App.Current.Resources["Standard250x250ItemTemplate"];
  }
}

Public Class ItemGridViewTemplateSelector
  Inherits DataTemplateSelector

  Protected Overrides Function SelectTemplateCore( _
        item As Object, container As DependencyObject) As DataTemplate

    Dim data As SampleDataItem = item
    If (data.UniqueId.Contains("Item-1")) Then
      Return App.Current.Resources("itemGridView2ndItemTemplate")
    End If
    Return App.Current.Resources("Standard250x250ItemTemplate")
  End Function
End Class

データ・テンプレートを切り替えるためのクラス(上:C#、下:VB)

 最後に、GroupedItemsPage.xamlファイルを書き変えて、上で作成したセレクタを使うようにする。

 まず、ファイルの先頭の方にあるPage.Resources要素の中に次のコードを追加して、セレクタのインスタンスを宣言する。

<local:ItemGridViewTemplateSelector x:Key="ItemGridViewTemplateSelector" />

Page.Resourcesに追加するコード(XAML)

 次に、GridViewコントロールでItemTemplateプロパティを設定している箇所を見つける(次のコード)。

【変更前】
ItemTemplate="{StaticResource Standard250x250ItemTemplate}"

削除するItemTemplateプロパティ(XAML)

 この行は削除し、代わりに次のコードを挿入する。

【変更後】
ItemTemplateSelector="{StaticResource ItemGridViewTemplateSelector}"

追加するItemTemplateSelectorプロパティ(XAML)

 以上で完了だ。実行すると、冒頭に掲げた画像のように表示される。

アイテム・コンテナ・スタイルを切り替えるには?

 アイテム・コンテナに適用するためのスタイルを複数用意しておき、StyleSelectorクラス(Windows.UI.Xaml.Controls名前空間)を継承して作ったセレクタで切り替える。

 GroupedItemsPage.xamlファイルでは、アイテム・グループの外観を指定するためにGridView.GroupStyleプロパティ内でItemsPanelTemplateとしてVariableSizedWrapGridコントロール(Windows.UI.Xaml.Controls名前空間)が指定されている。このVariableSizedWrapGridコントロールにはColumnSpan/RowSpanの2つの添付プロパティがあり、これらを指定することで複数のセルにまたがった大きなサイズでアイテムを表示できるようになるのだ。そこで、次の画像のように特定のアイテムだけ縦横2倍のサイズにしてみよう。

各グループで3番目のアイテムに別のスタイルを適用した画面 各グループで3番目のアイテムに別のスタイルを適用した画面

 この場合に注意すべきは、ColumnSpan/RowSpan添付プロパティを適用する先だ。これらのプロパティは、それぞれのアイテムではなく、アイテムを保持しているアイテム・コンテナに適用しなければならない。

 今回の場合は次の図のように、アイテムはDataTemplate(デフォルトのStandard250x250ItemTemplateと先ほど作成したitemGridView2ndItemTemplate)を使って表示しており(=緑色の枠)、その入れ物であるアイテム・コンテナはGridViewItem(=黄色の枠)である。そして、ColumnSpan/RowSpan添付プロパティの指定は、GridViewItemに対して行わなければならないのだ。この場合、テンプレート・セレクタではなく、アイテム・コンテナに対するスタイル・セレクタを使わなければならない。

GridViewItem(アイテム・コンテナ)とDataTemplate(アイテム) GridViewItem(アイテム・コンテナ)とDataTemplate(アイテム)
分かりやすいように、この画面ではGridViewItemとDataTemplateの間に紫色の隙間を作ってある。GridViewItemでVariableSizedWrapGridのColumnSpan/RowSpan添付プロパティを指定すると、この図のように複数セルにまたがった大きなセルになる。

 それでは、まず切り替えるスタイルから作っていこう。ここでは縦横2倍のサイズで表示するスタイルと、標準サイズのスタイルの2種類のスタイルを作る。これらも、「App.xaml」ファイルのResourceDictionary要素の中に追加する。

<!-- itemGridViewのアイテムのコンテナに適用するスタイル(標準) -->
<Style x:Key="itemGridViewContainer_NormalSize" TargetType="GridViewItem">
  <Setter Property="Width" Value="250" />
  <Setter Property="Height" Value="250" />
  <Setter Property="HorizontalContentAlignment" Value="Stretch" />
  <Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>

標準サイズのスタイル(XAML)

 上のコードは標準サイズのスタイルだ。幅と高さの250pxは、中に入るデータ・テンプレートに合わせてある。中に入るコンテンツの横方向/縦方向の配置を「Stretch」としてあるのは、後ほど説明する。

 次のコードは、縦横2倍のサイズで表示するスタイルだ。標準サイズのスタイルと比べて、幅と高さを2倍にしたほか、前述のColumnSpan/RowSpan添付プロパティの設定を追加した。

<!-- itemGridViewのアイテムのコンテナに適用するスタイル(2倍サイズ) -->
<Style x:Key="itemGridViewContainer_DoubleSize" TargetType="GridViewItem">
  <Setter Property="VariableSizedWrapGrid.RowSpan" Value="2" />
  <Setter Property="VariableSizedWrapGrid.ColumnSpan" Value="2" />

  <Setter Property="Width" Value="500" />
  <Setter Property="Height" Value="500" />
  <Setter Property="HorizontalContentAlignment" Value="Stretch" />
  <Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>

縦横2倍サイズのスタイル(XAML)

 次に、これら2つのスタイルを動的に切り替えるためのクラスを新しく追加する。クラス名は「ItemGridViewItemContainerStyleSelector」としよう。StyleSelectorクラスを継承させ、SelectStyleCoreメソッドを次のようにオーバーライドする。このメソッドにも表示しようとしているデータが引数として渡されるので、ここでは、表示するデータのUniqueIdプロパティに「Item-3」という文字列が含まれているときに、2倍サイズのスタイルを返すようにした。

class ItemGridViewItemContainerStyleSelector : StyleSelector
{
  protected override Style SelectStyleCore(
      object item, DependencyObject container)
  {
    var data = item as SampleDataItem;
    if (data.UniqueId.Contains("Item-3"))
    {
      return (Style)App.Current.Resources["itemGridViewContainer_DoubleSize"];
    }
    return (Style)App.Current.Resources["itemGridViewContainer_NormalSize"];
  }
}

Public Class ItemGridViewItemContainerStyleSelector
  Inherits StyleSelector

  Protected Overrides Function SelectStyleCore( _
        item As Object, container As DependencyObject) As Style

    Dim data As SampleDataItem = item
    If (data.UniqueId.Contains("Item-3")) Then
      Return App.Current.Resources("itemGridViewContainer_DoubleSize")
    End If
    Return App.Current.Resources("itemGridViewContainer_NormalSize")
  End Function
End Class

アイテム・コンテナ・スタイルを切り替えるためのクラス(上:C#、下:VB)

  最後に、GroupedItemsPage.xamlファイルを書き変えて、作成したセレクタを使うようにする。

 まず、ファイルの先頭の方にある「Page.Resources」要素の中に次のコードを追加して、セレクタのインスタンスを宣言する。

<local:ItemGridViewItemContainerStyleSelector
    x:Key="ItemGridViewItemContainerStyleSelector" />

Page.Resourcesに追加するコード(XAML)

 次に、GridViewコントロールの宣言部分を見つけ、次のコードを挿入する。

<GridView
  X:Name="itemGridView"
   ……
   ItemContainerStyleSelector
    ="{StaticResource ItemGridViewItemContainerStyleSelector}"
   ……

GridViewコントロールに追加するItemTemplateSelectorプロパティ(XAML)

 これで完成かと思って実行してみると、アイテム・コンテナを説明した図のようになってしまう。アイテム・コンテナのサイズは縦横2倍になったのだが、その中のデータ・テンプレートのサイズは元のままなのだ。これはアイテムのサイズを、テンプレートで指定したままになっているからだ。

 それを修正するには、Standard250x250ItemTemplateに指定されている幅と高さを削除する*2

<DataTemplate x:Key="Standard250x250ItemTemplate">
  <Grid HorizontalAlignment="Left"><!-- Width="250" Height="250" -->
                                   <!-- Width/Heightの設定を削除した -->
    ……

Standard250x250ItemTemplateから幅と高さの指定を削除する(XAML)

 すると、標準サイズのスタイルで指定したコンテンツの横方向/縦方向の配置(=「Stretch」)が効いて、アイテムがアイテム・コンテナ一杯に広がって表示されるのである。

 以上で完成だ。実行すると、冒頭に掲げた画像のように表示される。

*2 同様に、itemGridView2ndItemTemplateからも幅と高さの指定を削除する。今回の例では、このテンプレートは2倍サイズで表示されないので実害はないが、「標準サイズのスタイル」で幅と高さを指定するようにしたので、テンプレートでのサイズの指定は不要である。


  なお、このようにしてサイズの異なるセルを混在させたとき、並び順によっては次の画像のように「穴」が開いてしまうことがあるので注意してほしい。

並び順によっては「穴」が開いてしまうことも 並び順によっては「穴」が開いてしまうことも

まとめ

 GridViewコントロールやListViewコントロールでは、動的にテンプレートやスタイルを切り替えることができる。どちらも、新しいテンプレート/スタイルを用意し、セレクタのクラスを作り、画面のリソースにセレクタのインスタンスを定義し、GridView/ListViewコントロールの適切なプロパティにセレクタを指定する、という手順は同じである。

 2回にわたってGridView/ListViewコントロールの外観に変化を付ける方法を説明してきた。これには、ListViewコントロールで1行おきに色を変えたり、GridViewコントロールのグループの中にさらに小見出しを入れたりするなどといった、さまざまな応用が考えられる。この分野の日本語ドキュメントはまだ乏しい状況ではあるが、いろいろと試してみてほしい。

「WinRT/Metro TIPS」のインデックス

WinRT/Metro TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。