1|2■パネル(レイアウト用のUI要素)WPFには柔軟なレイアウトを簡単に実現するための仕組みが備わっている。ここでは、レイアウトの背景、基礎的な概念、および、標準で提供されているレイアウト用のパネルについて説明していく。●背景かつて技術が未成熟だったころ、GUIアプリケーションは固定レイアウト(要素のサイズや配置をすべてハード・コーディング)になることが多かったが、技術の進歩とともに、柔軟なレイアウトが可能となった。レイアウトを柔軟にすることには以下のような利点がある。以下に挙げるような理由から、GUIアプリケーションは環境ごとに表示方法が異なってくる。PCの場合、ディスプレイのサイズは機器ごとにかなりの差がある。ある人は全画面表示を好み、ある人は小さくしたウィンドウを複数並べることを好むなど、利用者ごとに好むウィンドウ・サイズが異なる。弱視や老眼の人の利用が想定される場合、フォント・サイズは容易にカスタマイズ可能にする必要がある。長さは使用言語ごとに異なり、特に例えば、漢字文化圏とアルファベット文化圏では長さが倍以上変わる場合もある。多言語対応が必要な場合に固定レイアウトを行っていると、言語によって文字が途中で切れるか、逆に余白が残りすぎるなどといった問題が生じる。柔軟なレイアウト手法によってサイズや配置を自動調整できれば、他言語対応に伴うGUIの再調整作業は必要なくなり、他言語対応の手間をほぼ翻訳の手間だけにできる。2に示すように、親子間で協調しながらサイズや配置を決定していく。親子間の協調のため、UIElementクラスには以下のようなメソッドが用意されている。要素が希望するサイズ。親要素から利用可能な領域サイズを渡し、DesiredSizeプロパティの値を更新する。実際に要素のサイズや配置を決定する。希望サイズを測るだけのMeasureメソッドと実際にサイズや配置を決定するArrangeメソッドに分かれているのは、正式にレイアウトを決定するまでの間に、ほかの要素との兼ね合いで何度も測り直しが発生するためである。○希望サイズの決定Measureでの希望サイズや配置の決定に当たって、FrameworkElementクラスは以下のようなプロパティを持っている。幅、高さを具体的に指定する。親要素によって希望サイズが拒否される可能性もあるため、必ずしもこの値が最終的なサイズにはならない。幅、高さの最小値、最大値を指定する。要素の外側の余白幅を指定する。配置される空間よりも要素のサイズの方が小さい場合に、要素を上下左右のどちらに寄せるかを指定する。WidthプロパティとHeightプロパティを用いることで、具体的な幅、高さを直接指定することも可能ではあるが、思ったとおりの見た目を得やすい半面、前述のような多様な表示方法への適応力が弱まるという問題もある。具体的な値の指定は可能な限り避けた方がいいだろう。このWidthプロパティやHeightプロパティはあくまで希望サイズを指定するためのものであって、レイアウト決定後の実際の値ではない。Number、無効な数値)のままになっている。レイアウト決定後の値を取得したい場合には、ActualWidthプロパティとActualHeightプロパティを利用する。●標準提供されるパネルWPFで標準提供されているパネルを紹介していこう。ここで紹介するクラスはいずれもPanelクラス(System.Windows.Controls名前空間)の派生クラスとなっている。○StackPanelStackPanelクラス(System.Windows.Controls名前空間)では、子要素を縦または横一列に整列する。6に示すようにOrientation属性で「Horizontal」を指定すると横に整列する。StackPanel(横)の例(XAML)○WrapPanelWrapPanelクラス(System.Windows.Controls名前空間)では、子要素を左から右に順番に並べ、幅を超えた分は右端で折り返すようにレイアウトする。HTMLでのインライン要素のレイアウトを想像するといいだろう。3にその実行結果を示す。WrapPanelの例(XAML)○DockPanelDockPanelクラス(System.Windows.Controls名前空間)では、パネルの上下左右に子要素を貼り付ける(ドッキング)ようにレイアウトする。ドッキングする位置はDockPanel.Dock属性(実体は添付プロパティ)によって行う。4にその実行結果を示す。DockPanelの例(XAML)○Canvasあまり場面は多くないが、どうしても固定レイアウトが必要なときにはCanvasクラス(System.Windows.Controls名前空間)を利用する。配置の指定はCanvas.Left属性やCanvas.Top属性(いずれも実体は添付プロパティ)を用いて行う。3にその実行結果を示す。○GridGridクラス(System.Windows.Controls名前空間)は、表形式(列位置と行位置の指定)でレイアウトを行う。Studioのウィンドウのテンプレートで使われているため、目にする機会は多いだろう。Studioの視覚デザイン・ツールを利用すると、表形式といっても、余白(Margin属性)やサイズ(Width属性とHeight属性)を使った固定的なレイアウトになりがちである。Windowsフォーム時代と同じ感覚でレイアウトができて手軽ではあるものの、多様な表示方法に対応するためには注意が必要である。表を何行・何列にするかや、各列の幅、各行の高さを決めるために、<Grid>要素のRowDefinitionsプロパティ、および、ColumnDefinitionsプロパティを設定する。列の幅、および、行の高さには、以下のように3種類の指定方法がある。「Width="100"」というように、数値のみを与えると、固定幅/高さになる。「Width="2*"」というように、数値の後ろにアスタリスクを付けると、比率指定となる。<Grid>要素自身のサイズ変更に応じて、比率を保ったまま行/列のサイズも変化する。「Width="auto"」というように、「auto」を指定すると、子要素のサイズに応じて行/列のサイズが自動調整される。子要素を何行目・何列目に配置するかを指定するため、Grid.Row属性、および、Grid.Column属性(いずれも実体は添付プロパティ)を設定する。複数行・複数列にまたがる子要素を作るためには、Grid.RowSpan属性およびGrid.ColumnSpan属性を指定する。5にその実行結果を示す。Gridの例(XAML)特に、「auto」はフォント・サイズの変更と相性がよい。多言語対応によって文字幅が変化した場合にも自動的に対応できる。この例では、コントロール・キーを押しながらマウス・ホイールを回すとフォント・サイズが変化するコードを記述している。<Grid>要素の行・列のサイズは「auto」を指定してあり、フォント・サイズの変化に、行・列のサイズが追従している。場合によっては、<Grid>要素の行・列のサイズを動的に変更したい場合もあるだろう。11に示すように、<Grid>要素の子に<GridSplitter>要素を配置する。GridSplitterの例(XAML)ただし、<GridSplitter>要素を利用する場合、以下のような注意点がある。<GridSplitter>要素自体、<Grid>要素のセルを1つ占有する。そのため、一般的には、<GridSplitter>要素を配置するための行・列を「auto」指定で作成しておく<GridSplitter>要素は、デフォルトの状態では幅も高さも「0」で不可視となる。HorizontalAlignment属性などを指定して、見えるサイズに調整する必要がある「特定の1行だけ列幅を変えたい」というようなことは、1つの<Grid>要素内では行えない。その必要があるなら、<Grid>要素を入れ子にして、内側の<Grid>要素だけに<GridSplitter>要素を追加するなどの工夫が必要になる○そのほかそのほかにも、いくつかPanelクラスの派生クラスがある。ここでは2つのクラスを簡単に紹介しておこう(いずれもSystem.Windows.Controls名前空間)。すべての行・列が同じサイズの単純な表形式でレイアウトを行う。柔軟性はないものの、描画の性能はよい。子要素を仮想化する(スクロールされるまで隠れていて見えない子要素を、実際に表示されるタイミングまで、サイズ計測も配置も行わない)ためのパネル。単体で利用するよりは、次回以降で説明するListBoxクラスなどの内部で利用する。●Z順序レイアウトの仕方によっては、UI要素が重なってしまう場合がある。このとき、特に指定のない場合、後方で(XAMLコード中の下の方で)定義されたUI要素が上に表示される。この順序(慣例的に「Z順序(Z-order)」と呼ばれる。横方向をX、縦方向をYで表すことが多いため、前後関係をZで表現する)を明示的に指定するには、UI要素にPanel.ZIndex添付プロパティを設定する。この添付プロパティの値が大きいほど手前に表示されることになる。●レイアウト丸めWPFでは、UI要素の位置を浮動小数点数で正確に位置を計算していて、自動レイアウトの結果、UI要素や文字の描画位置が非整数ドットになる場合がある。この際、デフォルトでは、補間処理によってUI要素が非整数ドット位置にあるかのように描画を行う。このような動作が好ましい場合ももちろんあるが、補間のせいで境界線や文字がにじんで見えるという問題もある。4では、FrameworkElementクラスにUseLayoutRoundingプロパティが追加され、このプロパティを「true」に設定すれば、描画位置が整数ドットになるように位置の丸め処理を行ってくれるようになった。次回は主にコントロールについて説明する。メールマガジンをご購読ください。申し込みページへITmediaはアイティメディア株式会社の登録商標です。