WPF DataGridのレイアウト設定はとかく複雑でわやよ。
今回は行の高さ指定に関する話。
DataGridには行の高さを指定できるプロパティがいくつもあるので
その適用の優先順位とか知っておかないと、
設定してるのに変わってくれないぞ??ってハマることになる。
<DataGrid RowHeight="20"><!-- (A) --> <DataGrid.RowStyle> <Style TargetType="DataGridRow"> <!-- (B) --> <Setter Property="Height" Value="30" /> </Style> </DataGrid.RowStyle> <DataGrid.CellStyle> <Style TargetType="DataGridCell"> <!-- (C1) --> <Setter Property="Height" Value="40" /> </Style> </DataGrid.CellStyle> <DataGrid.Columns> <DataGridTextColumn Header="列1"> <DataGridTextColumn.CellStyle> <Style TargetType="DataGridCell"> <!-- (C2) --> <Setter Property="Height" Value="50" /> </Style> </DataGridTextColumn.CellStyle> </DataGridTextColumn> </DataGrid.Columns> </DataGrid>
(A) DataGrid.RowHeightプロパティ
(B) DataGridRow.Heightプロパティ
(C1) DataGridCell.Heightプロパティ(DataGrid.CellStyleで指定)
(C2) DataGridCell.Heightプロパティ(DataGridColumn.CellStyleで指定)
以下、検証環境は.NET Framework 4.5.2 & Windows 8.1。
まずAとBの優先順について、MSDN「DataGrid.RowHeightプロパティ」には
RowHeight プロパティは、Height プロパティが設定されていない各 DataGridRow に適用されます
とあって、単純にAよりBを優先して採用しますって話に読めるんだけど、
そういう動きにはなっていない。
実際上記コードのようにAに20、Bに30を指定して(C1,C2は削除して)表示してみると
各行のスペースは30(Bの分)あるが、コンテンツ表示領域は20(Aの分)しか無いような
見え方(↓)になる。
逆にBを20、Aを30にしてやると、行幅は20しかないが、コンテンツ自体は
30の高さを持っているらしく、行間の罫線が見えなくなる。
この見え方から推測するに、DataGridRow.Height(B)で行の外枠を作ってから、
中に表示するコンテンツ(DataGridTextColumnならTextBlockだ)の配置領域を
DataGrid.RowHeight(A)で決めてるんじゃないかなと。
なので、DataGrid.RowHeightをいくら拡張しても
DataGridRow.Heightの値を大きくしないと表示領域は広くならない。
表示内容にあわせて自動で行高が拡張されるようにしたい場合は
DataGridRow.HeightとDataGrid.RowHeightの両方をAuto(既定値)に設定する必要がある。
ついでにいうと、RowHeightプロパティについて、MSDNには
コンテンツに合わせて行のサイズを自動調整するには、このプロパティを NaN (XAML では "Auto") に設定します
とあるが、これも嘘だ。
Aのとこに「RowHeight="Auto"」と書いてみると、ビルドエラーになる(B,Cは可能)。
RowHeightに明示的にAutoを指定したいときは、XAMLから書く時もDouble.NaNで書く必要がある。
<Window x:Class="DataGridRowHeightSample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib"> <DataGrid RowHeight="{x:Static sys:Double.NaN}"> ... </DataGrid> </Window>
System名前空間の定数は↑こんなふうに指定しますよ。
なかなかこういうのが書けそうで書けない、実は書けるのがXAML。
C1とC2の優先順については、C2が設定されている列についてはC2が優先される。
これはまあ違和感ないと思う。
A,BとCの関係については、まず、A,Bによって行自体の高さが決められてから、
その中で各列に配置されるセルの高さがCによって規定されるイメージっぽい。
Cにいくら大きな値を設定しても、A,Bで決められた値以上に
表示領域が拡張されることはない。
あんまり使い道ないと思うが、C2を使えば列ごとにセルの高さを変えることもできる。
先の例のようにAに20、Bに30を指定した状態で、
列2にだけDataGridCell.Height="10"を指定してやると↓こんな感じ。
あともちろん、表示内容にあわせて行高を自動拡張させる場合は
DataGridCell.HeightもAuto(既定値)にする必要がありますよと。
以上をふまえて、まとめ。
A:DataGrid.RowHeightをB:DataGridRow.Heightで上書きしたり、
B:DataGridRow.HeightをC:DataGridCell.Heightで上書きすることはできない。
なので、基本的にA,B,Cを併用するケースなんて無いと思ってよい。
行の高さを指定したいときは、AかBかCか、どれか1つだけ指定して、
あとは既定値Autoのままにしておくべし。
「他は行高20なんだけど、このDataGridだけは行高30にしたい」
というような場合は、BasedOnでStyleを継承するか、
Styleよりも直接プロパティ設定が優先されるというルールを利用すべし。