Windowsストアアプリ(XAML)でコレクション要素を思ったとおりに並べたい

今回は弊社初のWindowsストアアプリ「Ippin」の開発に絡めた記事です。すごく基本的な内容なのかもしれませんが情報が少なかったので残しておきます。

Windowsストアアプリ イッピン(Ippin) | 株式会社CFlat

XAMLではコレクションな要素を画面上に並べて配置したいときにはListViewやGridViewを使用します。

ListViewはこんな感じ、

GridViewはこんな感じのUIです。

ところがListViewやGridViewを使うとデフォルトでいろいろなプロパティが設定されていてすごく鬱陶しい。例えば要素間の間隔が10px空いていたりとか、選択時の見た目が予め決まっていたりとか。そして調整はすごく面倒。一体どのプロパティがどこに効いているのか、とてもじゃないけどわかりませんでした。

確かにWindowsストアアプリのレギュレーションで要素間の間隔なんかは決まっているのでデフォルトのスタイルがあってもいいんですが、そうじゃないよっていう場合もあります。もっと細かい調整をしたい、デザインと合わないから困るなんてことが実際にIppinの開発でもありました。つまり、余計なプロパティはなくていいから普通のStackPanelのように並べたいということです。

方法はいろいろ調べてみたら見つかりました。ListViewやGridViewの親であるItemsControlを使うという方法です。
まず結果を図で見せますが、1,2が普通のListViewで、3がVerticalなStackPanelを使ったItemsControlの場合です。

2はおまけとしてもらうとして、1と3を比べてください。1の各要素の上下左右にマージンがあるのがなんとなくわかると思います。このマージンなどのデフォルトスタイルが鬱陶しいのですが、スタイルをなくしてすっきりさせた結果が3です。いつの間にか設定されているマージンなどがなく、自由なレイアウトをできるようになりました。

この画像を作ったときのサンプルコードは以下のとおりです。

<!-- MainPage.xaml -->
<Page
    x:Class="App6.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App6"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Page.Resources>
        <DataTemplate x:Key="ListTemplate">
            <StackPanel Orientation="Horizontal" Margin="5">
                <TextBlock Text="{Binding Title}" FontSize="30"/>
                <TextBlock Text="{Binding Content}" FontSize="20"
Margin="10,0,0,0"/>
            </StackPanel>
        </DataTemplate>
    </Page.Resources>

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel Orientation="Horizontal" Margin="50">

            <!--1.普通のListView-->
            <ListView Background="DarkCyan"
ItemTemplate="{StaticResource ListTemplate}" ItemsSource="{Binding}"/>

            <!--2.横スタックパネルを使ったListView-->
            <ListView Background="DarkOrange"
ItemTemplate="{StaticResource ListTemplate}" ItemsSource="{Binding}"
Margin="10,0,0,0">
                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
            </ListView>

            <!--3.スタックパネルを使ったItemsControl-->
            <ItemsControl ItemsSource="{Binding}" Margin="10,0,0,0"
ItemTemplate="{StaticResource ListTemplate}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Vertical"
Background="DarkGreen"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </StackPanel>
    </Grid>
</Page>
//MainPage.xaml.csの一部
public sealed partial class MainPage : Page
{
  class Test
  {
    public string Title { get; set; }
    public string Content { get; set; }
  }

  public MainPage()
  {
    this.InitializeComponent();
    this.DataContext = Enumerable.Range(0, 5).Select(x => new Test {
Title = x.ToString(), Content = "content" });
  }

  /// <summary>
  /// このページがフレームに表示されるときに呼び出されます。
  /// </summary>
  /// <param name="e">このページにどのように到達したかを説明するイベント データ。Parameter
  /// プロパティは、通常、ページを構成するために使用します。</param>
  protected override void OnNavigatedTo(NavigationEventArgs e)
  {
  }
}