WPFのレイアウトのTips

WPFではパネルによって柔軟なレイアウトが可能ですが、時々意図通りにいかずイライラすることもあります。今回はちょっとヒントになるところをいくつか紹介します。

パネルとレイアウトのサンプル

レイアウト機能によるサイズ合わせのヒント

1.特定の大きさを指定する場合
対象要素のWidthやHeightを明示的に指定できます。MaxWidthやMinWidthでサイズの上限値や下限値を指定する方法もあります。(イメージ図の上左端)


2.親要素のサイズまで拡張する
親パネルの内側領域のサイズまで大きく引き伸ばすにはHorizontalAlignmentやVerticalAlignmentにStretchを指定します。ちなみに省略時の値(既定値)はStretchのため、明示的に指定していない場合にはこの状態になります。Buttonや単行テキストボックスなどの場合には間延びして不細工になりますが、パネルを入れ子にする場合には都合が良い場合もあります。(上中央)

ただし、一部のパネルでは引き伸ばしが無効になります。例えば、横方向配置のStackPanel (Orientation= Horizontal)ではHorizontalAlignmentがLeft指定のように動作しますし、Canvasでも無視されます。これは各種パネルのレイアウトの特徴を考えれば自然なことだと理解できます。


3.子要素のサイズまで縮小する
子要素などを表示できる最小限のサイズまでシュリンクさせるサイズ調整の場合には、HorizontalAlignmentやVerticalAlignmentにStretch以外のLeftやCenter、Topなどを明示的に指定します。(上右端)
ボタンなどで表示テキストにサイズを合わせることが多いと思うのでこのサイズ指定が都合が良いと思います。テキストよりも一回り大きなボタンにしたい場合は前述のようにWidthを用いても良いのですが柔軟性に欠けるためPaddingを使うと良いです。

    <UniformGrid Columns="3">

        <Grid>
            <Border BorderBrush="Gray" BorderThickness="1" >
                
                <!--1.特定の大きさを指定する場合-->
                <Button Content="指定値" Width="100" Height="100"/>
            </Border>
        </Grid>

        <Grid>
            <Border BorderBrush="Gray" BorderThickness="1" >
                
                <!--2.親要素のサイズまで拡張する-->
                <Button Content="親サイズにフィット"
                        HorizontalAlignment="Stretch" 
                        VerticalAlignment="Stretch" />
            </Border>
        </Grid>

        <Grid>
            <Border BorderBrush="Gray" BorderThickness="1" >
                
                <!--3.子要素のサイズまで縮小する-->
                <Button Content="中身に&#10;フィット" 
                        HorizontalAlignment="Center" 
                        VerticalAlignment="Center" />
            </Border>
        </Grid>

    </UniformGrid>


その他のヒント

親要素サイズ < 子要素サイズ の場合

1.の場合には親要素の表示領域から子要素が表示されます。2と3の場合には親サイズが優先されます。また、Gridなど通常のパネルでははみ出した部分は表示されなくなります(クリッピング)が、Canvasの場合にははみ出した部分も表示されてしまいます。これが不都合の場合にはClipToBounds=Trueにすることでクリッピングを有効にできます。

ウィンドウサイズを中身サイズに合わせて縮める

Window.SizeToContentプロパティをManual以外にすることで、内容に合わせてウィンドウサイズを自動的に調整できます。ただし極端に大きくなっても小さくなってもブサイクなのでMaxWidth/MinWidthを設定しておくと良いと思います。

ListBoxのアイテムの引き伸ばし・右寄せ

ListBoxのアイテムのデータテンプレートをカスタマイズする場合や背景色を設定する場合などに少々コツが必要です。3つのリストボックスは同じデータとデータテンプレートを使ってリストアイテムの背景色を指定していますがちょっと残念なことになっています(下左端)。データテンプレート内のGridやTextBlockのHorizontalAlignmentを指定しても効果がありません。この場合にはListBox.HorizontalContentAlignmentを指定してください。Stretchで引き伸ばし(下中央)、Rightで右寄せ(下右端)が有効になりました。

    <Window.Resources>

        <!--リストボックス用のテンプレート-->
        <DataTemplate x:Key="ListDataTemplate">
            <!--ここのパネルでHorizontalAlignmentを指定しても効かない-->
            <Grid Background="LightBlue" Margin="2">
                <TextBlock Text="{Binding}"/>
            </Grid>
        </DataTemplate>

        <!--リストボックス用のデータ-->
        <x:Array xmlns:sys="clr-namespace:System;assembly=mscorlib"
                 x:Key="ListData" Type="sys:String">
            <sys:String></sys:String>
            <sys:String>いい</sys:String>
            <sys:String>ううう</sys:String>
            <sys:String>ええええ</sys:String>
        </x:Array>
        
    </Window.Resources>

    <UniformGrid Columns="3">

        <ListBox ItemTemplate="{StaticResource ListDataTemplate}"
                 ItemsSource="{StaticResource ListData}" />

        <!--HorizontalContentAlignmentでリストアイテムを引き伸ばせる-->
        <ListBox ItemTemplate="{StaticResource ListDataTemplate}"
                 ItemsSource="{StaticResource ListData}"
                 HorizontalContentAlignment="Stretch" />

        <!--HorizontalContentAlignmentでリストアイテムを右寄せできる-->
        <ListBox ItemTemplate="{StaticResource ListDataTemplate}"
                 ItemsSource="{StaticResource ListData}"
                 HorizontalContentAlignment="Right" />

    </UniformGrid>
ListViewのアイテムの引き伸ばし・右寄せ

これも同様にできるようなのですが一ひねりが必要でなかなか分かりにくい。下のページを参考にしました。
http://www.slash-zero.jp/archives/program/550

結論をまとめると、ポイントは2カ所の設定が必須なことです。下のサンプルコードを参考にしてください。右寄せ(中央寄せ、Stretch)を利かせたカスタマイズが必要なのでGridViewColumnのDisplayMemberBindingプロパティを使えず、CellTemplateでテンプレートを設定する必要があります。テンプレートの中で右寄せしたいもののHorizontalAlignmentを設定します。ただしこの設定が利くようにするにはListViewItemのHorizontalContentAlignmentプロパティをStretchにしておく必要がある、という二段構えになっています。

    <ListView>
        <!--ポイント1:ListViewItemのHorizontalContentAlignmentをStretchにしておく-->
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            </Style>
        </ListView.ItemContainerStyle>

        <!--ポイント2:カラムのHorizontalAlignmentに所望の設定を行う-->
        <ListView.View>
            <GridView>
                <GridViewColumn Header="なまえ" Width="150">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Grid Background="LightBlue">
                                <TextBlock Text="{Binding}" HorizontalAlignment="Right" />
                            </Grid>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView>
        </ListView.View>

        <ListView.Items>
            <ListViewItem>ほげ</ListViewItem>
            <ListViewItem>ふが</ListViewItem>
            <ListViewItem>ふんが</ListViewItem>
        </ListView.Items>
    </ListView>