前々回WPFで作るウィンドウには一つのコンテンツしか入れられないので、コントロールが一つしか付けられないことが分かりました。また前回は(WinFormと対比しながら)ウィンドウの"Content"に入れるものの動作や特徴についても書きました。今回は先ずこれを深堀してみようと思います。

 

WPFはウィンドウをwebのページのように扱い、ページに表示するものをUI(User Interface)としてとらえているようです。webで色々とみていると、こんな図を見つけました。

UI要素のクラス階層:FrameworkElementからControl、Decorator、Panel等へ

 

そして、コントロールから派生するContentControlクラス(System.Windows.Controls名前空間)について、この図の出ている記事では「単一のデータに対するデータ・テンプレートの適用」という表現をして、「ボタンなどのように、コンテンツを1つだけ持つコントロールの基底クラスである。アプリケーション本体となることの多いWindowクラスもContentControlクラスから派生(解説:従って、コンテンツは一つしか持てない)している。」とし、「コンテンツを表すContentプロパティはobject型になっていて、何でも格納することができる。格納した型によって、以下のように、異なる表示が行われる。」とした後、

 

・UIElementクラスの場合、そのままUI要素として表示が行われる(OnRenderメソッドで描画を行う)
 ・そのほかのクラスの場合、データ・テンプレートが設定されていればテンプレートを使った表示が行われる
 ・データ・テンプレートも設定されていない場合、ToStringメソッドを使って文字列化された結果が表示される

 

と書いていますが、前回書いたContentに入れたオブジェクトの動作、即ち

(1)文字列は普通に表示される

(2)画像はそのサイズにより、縦か横一杯に表示される

(3)コントロールはクライアントエリア(ページエリア?)いっぱいに表示される

に対応しているようです。(オブジェクト毎にデータテンプレートが設定されているようです。)

 

更にその後、

ContentControlクラスの派生クラスの中に複数のUI要素を並べたい場合、

 (解説:①)まず<Grid>要素などのパネルを置いて

 (解説:②)その中にUI要素を並べる

という「解法」が述べられていました。

 

では、この「<Grid>要素などのパネル」とは何なのか、を↑の図で見ると、FrameworkElementから派生するPanelクラスに"Grid, StackPanel, WrapPanel, DockPanel, Canvas"というクラスが並んでいます。(

:名前空間はSystem.Windows.Controlsにあります。実はパネルには、この他にも

System.Windows.Controls.Primitives.TabPanel
System.Windows.Controls.Primitives.ToolBarOverflowPanel
System.Windows.Controls.Primitives.UniformGrid
System.Windows.Controls.Ribbon.Primitives.RibbonContextualTabGroupsPanel
System.Windows.Controls.Ribbon.Primitives.RibbonGalleryCategoriesPanel
System.Windows.Controls.Ribbon.Primitives.RibbonGalleryItemsPanel
System.Windows.Controls.Ribbon.Primitives.RibbonGroupItemsPanel
System.Windows.Controls.Ribbon.Primitives.RibbonQuickAccessToolBarOverflowPanel
System.Windows.Controls.Ribbon.Primitives.RibbonTabHeadersPanel
System.Windows.Controls.Ribbon.Primitives.RibbonTabsPanel
System.Windows.Controls.Ribbon.Primitives.RibbonTitlePanel
System.Windows.Controls.VirtualizingPanel

というものがあるそうな。
 

こいつらは皆ベースとなるPanel基底クラスのChildrenというUIElementCollection)のプロパティを持ち、Collectionものに共通のAddメソッドで子UIElementUI要素-コントロールのみならず、画像や文字列等)を複数持てるようにしています。

:要すれば、同じUIElementの配列を子供らとして持つようなもの-C++でいえば配列へのポインターのようなもの。

 

例えば簡単なStackPanelは、縦または横方向()に、コントロールを"<StackjPanel名>.Children.Add(<コントロール名>)”のように追加してゆきます。WrapPanelDockPanelは親ウィンドウのサイズを変化させたときの動作が異なりますが、概ねStackPanelと同様の取り扱いでよいです。

OrientationというプロパティにHorizontalまたはVerticalを設定する。

 

Gridはエクセルのように列と行でできた容れ物で、最初に列と行を作ってやる必要があります。後はコントロール等UIElementをマトリクスのどこに入れるか指定し()、同じく"<Grid名>.Children.Add(<コントロール名>)”で子分にして終わりです。

SetColumn/SetRow(<UIElement名>, <0ベースの順番>)というメソッドを使います。

 

CanvasはWin32APIやWinFormの相対座標に慣れた方にやさしい容れ物で、ウィンドウのContentにCanvasを指定するとクライアントエリアいっぱいに広がるので、後は入れるUIElementをの位置を指定()し、"<Canvas名.Children.Add(<UIElement名>)”で子分にしてやります。

Canvas.SetTop(<UIElement名>, 上からのオフセット) Canvas.SetLeft(<UIElement名>, 左からのオフセット)というメソッドを使います。

 

どうでしょう?

 

イメージがわきましたか?

 

要すれば、インターネットとの親和性を高めるために、コントロールや図形、イメージ、文字列等コンテンツの柔軟なレイアウト、区割り、配置を行えるようにし、その為にGrid, StackPanel, WrapPanel, DockPanel, Canvas等が採用され、ウィンドウをwebページのようにデザインするプロセスにしたんですね。その必然の結果としてUI(View)についてはXaml表記が導入され、その裏方処理("Code-Behind"()によるModel)はC#表記という「分離コード」へ発展したということのようです。

ASP.NETというMicrosoftのウェブプログラム開発フレームワークで使われる概念です。("Code-behind is a concept commonly used in ASP.NET web development.")webデザインのHTMLとは別の言語による処理コードを意味します。("Code-behind refers to code for your ASP.NET page and  allows a clean separation of your HTML from your presentation logic.")

 

まぁ、そんなこたぁどうでもよくって、

 

問題はどうサンプルを書いたらいいのか、ということになりますね。そいつは次回に回しましょう。

 

【ご参考】

Microsoft Learnーコントロール