Release Preview における GridView の問題点 (2)
Release Preview 上で Visual Studio 2012 RC のテンプレートを使って生成したプロジェクトに、GridView や ListView のマージンに関する問題がある事がわかりましたので、解決方法について検討してみたいと思います。
問題点は GridView の右側、ListView の下側のマージンが正しく設定されないという物です。
現象の確認
まず、問題の詳細を確認するために Blend で Grid App を作成し、GridView のスタイルをコピーしてみます(GridView を選択して右クリックのメニューから [テンプレートの編集] - [コピーして編集] を実行)。
中身を見てみると GridView の Padding に指定した値を ItemsPresenter の Padding に設定するようになっています。
<Style x:Key="CustomGridViewStyle" TargetType="GridView"> <Setter Property="Padding" Value="0,0,0,10"/> : : <ItemsPresenter HeaderTemplate="{TemplateBinding HeaderTemplate}" Header="{TemplateBinding Header}" HeaderTransitions="{TemplateBinding HeaderTransitions}" Padding="{TemplateBinding Padding}"/> : : </Style>
内容だけを見ると正しく動きそうですが、Padding のスクロール方向の値(Grid App の GridView の右、ListView の下)だけ正しく反映されていないようです。
ItemsPresenter の Padding に直接数値を設定しても、スクロール方向の値だけ反映されません。
Margin の値は正しく反映されるようなので、Padding ではなく Margin に設定するように変更してみました。
<ItemsPresenter HeaderTemplate="{TemplateBinding HeaderTemplate}" Header="{TemplateBinding Header}" HeaderTransitions="{TemplateBinding HeaderTransitions}" Margin="{TemplateBinding Padding}"/>
これで一見正しく動いているように見えたのですが、グループを使っていない GridView(Split App で作成した物が該当)をこのスタイルで動かしてみると、右側のマージンはきちんと取られますが、スクロールした時に左側が画面いっぱいに表示されず常にマージンがあるような形で表示されてしまいます。
対応方法
確認した内容を検討すると、ItemsPresenter の Padding に設定されている値の内、GridView の場合は Right、ListView の場合は Bottom のみを Margin の方に設定すれば想定通りに動作しそうです。
以前も試した通り Margin に直接値を記述したスタイルを複数用意して、必要に応じて切り替える事で対応できると思いますが、この方法は設定値が違う場合は別のスタイルとして定義しなければならないため面倒ですし、ポートレートビューになった時はスタイルを切り替える必要があります。
せっかくテンプレートで作成した xaml にポートレートビュー切替時の動作(Padding の値を変更する)が入っていますので、できればこれを生かした形でという事で Padding に設定されている値を Margin にバインドする方法で対応してみたいと思います。
単純に Padding の値を Margin にバインドするだけであれば、以下のような xaml で対応できます。
<ItemsPresenter HeaderTemplate="{TemplateBinding HeaderTemplate}" Header="{TemplateBinding Header}" HeaderTransitions="{TemplateBinding HeaderTransitions}" Padding="{TemplateBinding Padding}" Margin="{Binding Padding, RelativeSource={RelativeSource Mode=Self}}"/>
しかし、この対応では Padding の全ての値が Margin にそのまま設定されてしまいますので、左端等は二重に余白がとられてしまいます。
今回やりたい事は、Padding の Right または Bottom のみを Margin に設定する事ですが、xaml だけで行う方法が見つけられませんでしたので、コンバーターを作成して対応しました。
コンバーターのソースは以下のような物で、渡された Thickness の Right または Bottom だけを使い、その他は 0 に変換します。
public class RightMarginConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { var margin = (Thickness)value; return new Thickness(0, 0, margin.Right, 0); } public object ConvertBack(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); } } public class BottomMarginConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { var margin = (Thickness)value; return new Thickness(0, 0, 0, margin.Bottom); } public object ConvertBack(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); } }
作成したコンバーターを
<common:RightMarginConverter x:Key="RightConverter"/> : <ItemsPresenter HeaderTemplate="{TemplateBinding HeaderTemplate}" Header="{TemplateBinding Header}" HeaderTransitions="{TemplateBinding HeaderTransitions}" Padding="{TemplateBinding Padding}" Margin="{Binding Padding, RelativeSource={RelativeSource Mode=Self}, Converter={StaticResource RightConverter}}"/>
この対応で、グループを使用している物も使用していない物も同じ方法で適切なマージンが設定されるようになります。
ListView に関しても対応方法は同じです(BottomMarginConverter を使います)。
注意事項
今回の対応は Blend でプロジェクトを作成してスタイルコピーを行い、その後 Visual Studio で開きなおしてコンバーターの追加等を行いました。
この手順で作業を行い Visual Studio 側でビルドする時に、証明書ファイルが読み込めないというエラーが発生しました(確実に発生するのかまでは確認していません)。
このようなエラーが発生した場合、Package.appxmanifest をダブルクリックして開き、[パッケージ化]タブの[証明書の選択]ボタンを押して、[テスト証明書の作成]を行うと正常にビルドできるようになります。
まとめ
今回行ったような対応で適切なマージンを持つようにできますが、次のリリース時にはまた何らかの対策が行われると思います。
現時点でこのような対応を行っても対策が行われて無駄になる可能性が高いですし、Consumer Preview の時のようにキーボードやマウスでの操作に支障があるといった問題ではありませんので、どうしても必要な場合を除いては対応は行わずに対策を待った方が良いでしょう。