適切なマージンを持った GridView のスタイル定義 (1)

 ※Release Preview での状況は以下の記事を参照してください。
 Release Preview における GridView の問題点 (1) - rebuild

 以前(GridView の仮想化 - rebuild)書いた通り、現状の Visual Studio 11 Beta でテンプレートを使ってプロジェクトを作成した場合、ScrollViewer の中に GridView や ListView が配置されるため、いくつか動作に問題があります。

  • コントロール内部のアイテムが仮想化されない。
  • マウスのホイールでスクロールされない。
  • カレントアイテム(白い枠が表示されている物)をキーボードで移動していってもスクロールされず、カレントアイテムが画面外になってしまう。

 これらの問題を解決する方法としては、ScrollViewer の外に GridView / ListView を配置する事が考えられます。
 これによって問題は解決しますが、今後はマージンが適切に設定されなくなってしまいます。

 マージンの問題に関しては、これも前回紹介しましたがスタイルを定義して解決する方法を書かれている方がいます(程よい余白を持ったGridViewを定義しよう - かずきのBlog@hatena)。
 今回はまずスタイルを定義してマージンを設定する手順を確認してみたいと思います。

スタイル定義

 今回の作業は Blend の方がやり易いので Blend でグリッドアプリケーションのプロジェクトを作成します。
 作成されるプロジェクトは Visual Studio で作成した場合と同じ物です。

 プロジェクトを作成したら一度ビルドしておきます。
 ビルドすると“オブジェクトとタイムライン”に画面上のコントロールツリーが表示されるようになります。

 スタイル定義を行う前に、スタイルを定義するリソースディクショナリファイルを作成します。
 これは、追加したファイルに定義する事で再利用可能とするためです。
 リソースディクショナリはプロジェクトタブ上で「新しいアイテムの追加」を実行し、リソースディクショナリを選びます。

 スタイルを定義する場合、元々のスタイルをコピーして編集すると簡単なので、まずはスタイルをコピーします。
 コピーを行うにはコントロールツリー上の GridView を選択して右クリックし、表示されるメニューから「テンプレートの編集」-「コピーして編集」を実行します。

 定義先は先程追加したリソースディクショナリを選択します。

 これでリソースディクショナリに GridView の標準状態でのスタイルがコピーされましたので、これを変更します。

 変更する箇所は、ScrollViewer の中に配置されている ItemsPresenter のみです。
 ItemsPresenter は実際に GridView に追加された項目を表示する場所です。
 この部分に適切なマージンが設定されていればいいので、ItemsPresenter のマージン設定を追加します。
 設定する値は、テンプレートで GridView 自体に設定されている値です。

<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="GridView">
            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
                <ScrollViewer x:Name="ScrollViewer" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" Padding="{TemplateBinding Padding}" TabNavigation="{TemplateBinding TabNavigation}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
                    <ItemsPresenter Margin="116,0,40,46"/>
                </ScrollViewer>
            </Border>
        </ControlTemplate>
    </Setter.Value>
</Setter>

 このスタイルを GridView で使用されるように設定(スタイルをコピーした場合はすでに設定されています)すれば、適切なマージンを持った形で動作します。
 GridView 単体でマージンを持った形で動作するようになりましたので、ScrollViewer から外に出します。
 GridView の Grid.Row や Margin は、ScrollViewer に設定されていた通りにします。
 ScrollViewer は削除してしまってかまいません。

 この状態で実行すると適切なマージンが設定されている事、ホイールでのスクロール等が可能になっている事が確認できます。


画面左に適切なマージンが設定されている


途中のスクロール中は画面いっぱいに表示されている


画面右にも適切なマージンが設定されている

 これで画面が横になっている場合は問題なく動作しますが、画面を縦にしてポートレート表示にすると左右のマージンが大きすぎて問題があります。

 元々のテンプレートを見るとわかりますが、ポートレート表示にした場合は、GridView のマージンを変更する事で適切な表示が行われるようになっています。
 スタイルにマージンを定義してしまったため、ポートレート表示にした時のマージン変更が適切に行われなくなった事が問題の原因です。

 次回は、ポートレート表示でも適切なマージンになるようにしてみたいと思います。