必要なXAMLの知識を得たところで、筆者が一番初めに紹介したいのはレイアウトである。単純にコントロールを画面に配置するといった用途以外でも、このレイアウトが重要となるシーンは多いため、確実に押さえておきたい部分だ。
WPF UIフレームワークにおけるレイアウトは、主にPanel(=Panelクラスの派生クラスにマッピングされた要素全般を指す)を用いて行うことになる。ここでは代表的な下記の3つのPanelを紹介する。
●Canvas
Canvasは、Windowsフォーム・アプリケーションの開発者にはなじみ深い絶対配置をサポートするPanelだ。WPF UIフレームワークで絶対配置をサポートするのは、このCanvasだけであり、そのほかのPanelやレイアウト要素はすべて相対配置となる。
Canvasの例を下に示す。
<Canvas>
<Button Canvas.Top="50" Canvas.Left="50"
Content="ボタン A"/>
<Button Canvas.Top="180" Canvas.Left="100"
Height="80" Width="250" Content="ボタン B"/>
</Canvas>
Canvasの左上端を起点とし、Canvas.Top添付プロパティで上端からの距離を、Canvas.Left添付プロパティで左端からの距離を指定する。
実際には親要素(この例では<Canvas>要素)で定義されているプロパティ(この例ではTopプロパティやLeftプロパティ)に、子要素(この例では<Button>要素)がそれぞれ別の値を指定できるプロパティ。
絶対配置で利用されるTopプロパティとLeftプロパティは、WPF UIフレームワークでは親要素がCanvasである場合しか必要のないプロパティであるため、(各子要素には実装されずに)Canvasの添付プロパティとして実装されている。このおかげで、個々の子要素は、Canvasに配置されたときのみ、そこで必要なプロパティを利用できる。
ここで1つ注目してほしいのがCanvasに配置された子要素(今回の例では<Button>要素)のサイズである。[ボタン B]ボタンはHeightプロパティとWidthプロパティに値を設定しているため、設定された高さと幅で表示されている。
一方、[ボタン A]ボタンについては値を設定していないため、デフォルト値が適用されることになる。HeightプロパティとWidthプロパティのデフォルト値は、「Double.NaN」(XAMLにおける記述は「Auto」)となっており、これは自動サイズを有効にする設定値である。自動サイズの振る舞いは親となるPanelによって異なり、その要素の内容がすべて表示される最小限の長さになるというのが、Canvasにおける自動サイズの振る舞いだ。
なお、WPFでは、下端からの距離を指定するCanvas.Bottom添付プロパティと右端からの距離を指定するCanvas.Rightプロパティも存在する。ただし、あくまでTopとLeftが優先されるため、例えばTopとBottomの両方に値を設定した場合には、Buttonに設定した値が無効となる。
●StackPanel
StackPanelは、要素を垂直方向または水平方向に積み重ねていくようなレイアウトをサポートするPanelだ。Windowsフォームで2.0から追加されたFlowLayoutPanelコントロールと同様のレイアウト方法をサポートしている。
下記のコードのように、単純にStackPanelに<Button>要素を2つ追加した場合、レイアウトは下の画面のように2つのボタンが垂直方向に整列された状態となる。
<StackPanel>
<Button Content="ボタン A"/>
<Button Content="ボタン B"/>
</StackPanel>
先ほどのCanvasの場合とは、自動サイズの振る舞いが異なっていることに気付いただろうか。高さについてはCanvasと同じ振る舞いだが、幅がStackPanelと同じサイズ、つまり設定可能な最大の幅になっている。
実は自動サイズに影響するプロパティとして、垂直方向または水平方向の配置の特性を設定するVerticalAlignmentプロパティとHorizontalAlignmentプロパティが存在する。次の画面は4つの<Button>要素を配置して、HorizontalAlignmentプロパティにそれぞれ異なる値を設定した例だ。
<StackPanel>
<Button Content="ボタン A" HorizontalAlignment="Stretch"/>
<Button Content="ボタン B" HorizontalAlignment="Left"/>
<Button Content="ボタン C" HorizontalAlignment="Center"/>
<Button Content="ボタン D" HorizontalAlignment="Right"/>
</StackPanel>
上記のコードのように、HorizontalAlignmentプロパティに「Stretch」(デフォルト値)以外の値(具体的には「Left」「Center」「Right」)を設定した場合、その横幅は(Canvasのときと同様に)要素の内容がすべて表示される最小限の長さになり、それぞれ左端、中央、右端にレイアウトされることが分かる。実はCanvasの場合、絶対配置であるためにこのVerticalAlignmentプロパティとHorizontalAlignmentプロパティが無視される動作になっている。
StackPanelの場合、デフォルトでは垂直方向に対して要素が整列されることになるため、HorizontalAlignmentプロパティのみ有効となり、VerticalAlignmentプロパティは無視される。StackPanelはOrientationプロパティで整列の方向を垂直か水平のどちらかに設定でき、水平の場合にはこの逆の動作となる。
Orientationプロパティが「Horizontal」で水平方向への整列、「Vertical」で垂直方向への整列となる。デフォルト値は「Vertical」。下の画面は、StackPanelのOrientationプロパティに「Horizontal」を設定し、その中に<Button>要素を4つ配置し、それぞれのVerticalAlignmentプロパティに「Stretch」「Top」「Center」「Bottom」を設定した例。
<StackPanel Orientation="Horizontal">
<Button Content="ボタン A" VerticalAlignment="Stretch"/>
<Button Content="ボタン B" VerticalAlignment="Top"/>
<Button Content="ボタン C" VerticalAlignment="Center"/>
<Button Content="ボタン D" VerticalAlignment="Bottom"/>
</StackPanel>
忘れてはならないのは、StackPanelは相対配置であるということだ。これはStackPanel自体のサイズが変化したときに初めて意味を持ってくる。以下の画面は、上の画面「StackPanelによる水平配置の表示例」のStackPanelの高さを半分にした状態の表示である。
さらに、相対配置の際に重要となるプロパティとしてMarginプロパティが存在する。Marginプロパティはその要素に対して上下左右の余白を付加するプロパティである。例えば下の画面では[ボタン B]と[ボタン D]の2つのボタンに対し、Marginプロパティを設定している。
<StackPanel>
<Button Content="ボタン A"/>
<Button Content="ボタン B" Margin="150,40,80,40"/>
<Button Content="ボタン C"/>
<Button Content="ボタン D" Margin="10"/>
<Button Content="ボタン E"/>
</StackPanel>
XAMLにおける記述方法として、四辺に対してそれぞれ余白を設定する場合には、[ボタン B]のように「左,上,右,下」の順にカンマ区切りで数値を設定する。四辺の余白をすべて同じ大きさにする場合は、[ボタン D]のように単一の値を設定すればよい。
各レイアウト動作は、このMarginプロパティによる余白を含んだ形で各要素を取り扱うことになる。なお、MarginプロパティはCanvasでも有効ではあるが、絶対配置で余白が必要となるケースはあまりないだろう。
Copyright© Digital Advantage Corp. All Rights Reserved.