概要
WPFの入力フォームで、左にラベル、右に入力欄、というペアを縦に並べることはよくありますよね。こういうのです。

ここでよく要望されるのが、ラベルの文字数に関係なく、入力欄の左端を全部揃えることです。Gridで実現出来ますが、普通に書くと今ひとつ綺麗にならず保守性も良くない。そういう時に良い書き方を紹介します。
最初に結論まとめ
- Grid の SharedSizeGroup を使えばOK
- 共通の親要素に Grid.IsSharedSizeScope="True" を付ける
- ラベルと入力欄の1つのペアをそれぞれ小さい Grid にし、ラベル列に同じ SharedSizeGroup を付ける
- これだけで、論理的な「ラベルと入力欄」というペアと、コード上の配置が、綺麗にまとまる!
- 大量に行が有る場合はさらに、1行分を UserControl にして並べると、さらに見通しが良くなる
(記事が短いのでコードサンプルはここには書きません。コードサンプルはこの後を読んでください)
説明
全体を1つのGridにすると少し扱いづらい
幅を揃えるだけなら、全体を1つの Grid にして、左列をラベル、右列を入力欄にするのが素直です。
ただ、項目を下に追加する度にGridの上に RowDefinition を増やす必要があり、書いていて少し手間に感じます。
もう1つ気になるのが、論理的には「ラベルと入力欄で1項目」なのに、XAML上では別々に置く形になりやすいことです。つまり、論理的なまとまりとコードがズレてしまうので・・・たとえば特定の入力項目だけマージンを大きくしたいといった場合、ラベル側と入力欄側で別々に実装を入れるという、やりづらいコードになります。
SharedSizeGroup を使うと「1項目1グリッド」で揃えられる
これは SharedSizeGroup を使うときれいに書けます。
共通の親要素に Grid.IsSharedSizeScope="True" を付けて、ラベルと入力欄の1つのペアをそれぞれ小さい Grid にし、ラベル列に同じ名前の SharedSizeGroup を付けます。(名前は自由です)
<StackPanel Grid.IsSharedSizeScope="True" Orientation="Vertical" Margin="5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="名前"/>
<TextBox Grid.Column="1" MinWidth="240"/>
</Grid>
<Grid Margin="0,18,0,6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="メールアドレス"/>
<TextBox Grid.Column="1"/>
</Grid>
</StackPanel>
これで、各行は独立した Grid のままなのに、ラベル列の幅だけは共通化できます。
これならば、「項目のラベルと入力欄」という論理的なまとまりが、コード上も1つにまとまります。
特定のラベル・入力欄セットだけ Margin を変えたい、といった調整も自然に書きやすいですね。(上のコードでは0,18,0,6のマージンをまとめて付けています)
新たな行を追加するときに、新たなGridを追加するだけで良いというのも自然で良い感じです。(親の RowDefinition と整合を取るような手間がいらない)
注意点
SharedSizeGroup を付けた ColumnDefinition は、Width="*"(Star指定)が効かず、Auto として扱われるようです。このサンプルのようにラベル列を Auto で使う分には問題ありませんが、応用する場合は注意です。
繰り返しが多いなら UserControl 化しておく
同じ形の行がたくさん出るなら、1行分を UserControl にして並べる形にもできます。
次のサンプルのようになりますが、だいぶコードは増えるので、アプリ内に大量に同じようなものがあるときにおすすめです。
※ x:Name でテキストボックスへアクセス出来ますが、データバインディングまでは考慮して試していません
まとめ
入力欄の左端は揃えたいけど、行単位のまとまりも崩したくない、というときは SharedSizeGroup がかなり便利です。業務アプリ系ではよくあると思うので、ぜひ使ってみてください。
