WPFでGridを使ってGUI部品をきれいに配置するための考え方。
初めに
VisualStudioのWPF GUI構築ツールでは、Grid状に部品をDrag&Dropして配置すると、右・上からのマージン指定での配置となってしまう。
この場合、部品の位置指定が座標値指定となってしまうため、例えば多言語化対応時に、ラベル内のテキストに変更があると、配置のずれが発生してしまう。
例えばラベルの右隣にボタンを配置した例で示すと、ラベルのテキストが長いものに変更された場合、下の図のようにラベルがボタンの上に重なってしまう状態になる。
→
Gridを使った配置
ある程度部品の大きさが変わっても、自動でいい配置になるようにするためのGridの使い方について記述する。
GUI部品の配置のラフイメージの作成
部品の位置関係を把握するため、どのような部品をどこに配置するか、手書きでもいいので、書き上げる。
部品の整列状況をイメージしてグループ化する
PowerPointの配置を使った場合、どのような部品をグループ化して整列配置をするかを考える。例えば、上の例だと、2つの左揃えと、4つの中央ぞろえでまずそろえてみる。
なお、黒点線にかかる部品が、整列配置時のグループ化した部品になる。
(リストは複数の配置線をまたぐので、別途検討)
Gridの分割数の検討
基本的に、整列配置した時の基準となるグルーピングの数で、行列数を決定する。上の例だと、2列、4行。
(リストは複数の配置線をまたぐので、別途検討)
この内容で、まず部品を配置してみると、次のようになる。ただ、行列の高さ・幅はAutoで、部品のマージンは0で配置する。
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1"/>
<Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="2"/>
<Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="3"/>
<Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1" Grid.Column="1"/>
<ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="コンボ" IsEditable="True" Grid.Row="1" Grid.Column="1"/>
<Button Content="ボタン" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Grid.Row="3" Grid.Column="1"/>
<RadioButton Content="ラジオ" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Grid.Row="2" Grid.Column="1"/>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="1"/>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="1"/>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Row="1" Grid.Column="1"/>
</Grid>
2列目の部品は、まだ配置が完了していないため、まとまって表示されている。次に、この部品を配置する。
この部品は、横に並べるため、2列目にGridを配置し、その子供として再配置する。
子供のGrid
1,2行目は、それぞれ2部品、3部品を配置するので、2列、3列の2つのGridを使い配置する。この場合、0行目,1列目にあったテキストと、1行目,1列目にあったコンボボックス、ラベル、テキストを、Gridに押し込む。
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="0"/>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="1"/>
</Grid>
<Grid Grid.Row="1" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="1"/>
<ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="コンボ" IsEditable="True" Grid.Column="0"/>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="2"/>
</Grid>
これで、リストを除く部品については、グリッドに乗せた配置ができた。
後のは、Margin, Alignmentを使い、部品の位置を微調整する。
Gridに乗らなさそうな部品の配置
サンプルでは、リストが2つの行にまたがって配置している。このような部品は、RowSpanやColumnSpanを使い、いくつの行/列にまたがって配置するか示す属性を使う。
今回のケースでは、リストの右で区切り、親のGridを3列4行にしたい。しかし、ここで区切ると、すでに子供のGridで配置したものがそのままでは2列目に押し込められてしまうので、この部分も、2,3列目にまたがるように再調整する。
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.Column="1" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="0"/>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="1"/>
</Grid>
<Grid Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="1"/>
<ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="コンボ" IsEditable="True" Grid.Column="0"/>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="2"/>
</Grid>
<Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1"/>
<Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="2"/>
<Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="3"/>
<Button Content="ボタン" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Grid.Row="3" Grid.Column="1"/>
<RadioButton Content="ラジオ" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Grid.Row="2" Grid.Column="1"/>
<ListBox Grid.Row="2" Grid.Column="2" Grid.RowSpan="2">
<ListBoxItem Content="List"/>
<ListBoxItem Content="List"/>
<ListBoxItem Content="List"/>
<ListBoxItem Content="List"/>
</ListBox>
</Grid>
これで、当初想定した位置関係で部品が配置できた。
微調整
後は、部品の幅/高さ/マージン/整列位置の調整などを行うことで、綺麗な配置のGUIが出来上がると思う。
一応の完成形。
Listが2行の場合、3,4行目の高さが大きくなってしまうため、親Gridをもう1行増やし、リストは3行にまたぐ設定とした。
まとめ
Gridを再帰的に配置し、必要であれば、複数列/行をまたぐ設定をすることで、部品をきれいに整列配置することができた。
コメント