私が勉強で使っているテキストはこちらです。
Windows Presentation Foundation プログラミング入門
- 作者: 赤坂玲音
- 出版社/メーカー: 秀和システム
- 発売日: 2007/04/26
- メディア: 単行本
- 購入: 2人 クリック: 19回
- この商品を含むブログ (18件) を見る
今回は勉強するための環境作成と3章の「パネルとレイアウト」についてまとめます。
分類 | 私の環境 |
---|---|
OS | Windows Vista SP1 |
Framework | .NET Framework3.5 |
editor | gvim 7.1 |
テスト環境作成
いつもIDEを使って開発をしていたので、今回のようにIDE無しの環境でプログラムを作るのが面倒に感じられます。ちょっと手抜きをするために、ソースのテンプレートを準備してそれをコピーするバッチファイルを作成しました。
今回、開発をするにあたってフォルダ階層はこのようにしました。
d:\pg\WPF>tree /F フォルダ パスの一覧 ボリューム シリアル番号は 0006F240 2862: D:. │ c.bat │ ├─exe │ ├─source │ └─template template.cs
で、テンプレートファイルをコピーするバッチファイルを作成しました。ファイル(D:\pg\WPF\c.bat)の中はこんな感じです。
@ECHO OFF CLS :SELECTPROCESS ECHO テンプレートファイルを作成しますか? SET /PMKFILE=[Y:作る/N:作らない/D:一覧表示] DEL .\*.*~ > NUL MOVE *.exe .\exe > NUL MOVE *.cs .\source > NUL IF /I "%MKFILE%" EQU "D" GOTO SOURCEVIEW IF /I "%MKFILE%" EQU "Y" GOTO MAKEFILE IF /I "%MKFILE%" EQU "N" GOTO FINISH :SOURCEVIEW CLS ECHO ● ソースファイル一覧 DIR /ON "%~dp0source\*.cs" | FIND /I ".cs" GOTO SELECTPROCESS :MAKEFILE CLS SET NEWFILENAME=sample.cs ECHO ファイル名を入力してください[止める場合は.を入力] SET /PNEWFILENAME=[初期値:%NEWFILENAME%]? IF /I "%NEWFILENAME%" EQU "." GOTO FINISH COPY /Y "%~dp0template\template.cs" .\%NEWFILENAME% VI.EXE "%~dp0%NEWFILENAME%" :FINISH CLS
チョーシンプル。Simple is Bestです。
で。テンプレートファイル(D:\pg\WPF\template\template.cs)はこんな感じです。
using System; using System.Windows; using System.Windows.Controls; class Test { [STAThread] public static void Main(){ Window wnd = new Window(); Application app = new Application(); app.Run(wnd); } }
今後、パターンが増えてきたらもう少しいいテンプレートを考案します。
というわけで開発環境の作成は終わり。
第3章 パネルとレイアウト
キャンバス
画面上にボタンなどを配置するためにCanvasクラスを利用します。
では画面上にボタンを重ね合わせて表示して、押されたボタンが最上位に移動するようなプログラムを作成してみます。
using System; using System.Windows; using System.Windows.Media; using System.Windows.Controls; class Test { [STAThread] public static void Main(){ Button button1 = new Button(); button1.Content = "button1"; button1.FontSize = 50; Canvas.SetLeft(button1,10); Canvas.SetTop(button1,10); Canvas.SetZIndex(button1,0); Button button2 = new Button(); button2.Content = "BUTTON2"; button2.FontSize = 50; Canvas.SetLeft(button2,100); Canvas.SetTop(button2,30); Canvas.SetZIndex(button2,2); Button button3 = new Button(); button3.Content = "ボタン3"; button3.FontSize = 50; Canvas.SetLeft(button3,200); Canvas.SetTop(button3,50); Canvas.SetZIndex(button2,2); button1.Click += (sender, e) => { Canvas.SetZIndex(button1,2); Canvas.SetZIndex(button2,1); Canvas.SetZIndex(button3,0); }; button2.Click += (sender, e) => { Canvas.SetZIndex(button2,2); Canvas.SetZIndex(button3,1); Canvas.SetZIndex(button1,0); }; button3.Click += (sender, e) => { Canvas.SetZIndex(button3,2); Canvas.SetZIndex(button1,1); Canvas.SetZIndex(button2,0); }; Canvas cnvs1 = new Canvas(); cnvs1.Children.Add(button1); cnvs1.Children.Add(button2); cnvs1.Children.Add(button3); Window wnd = new Window(); wnd.Content = cnvs1; Application app = new Application(); app.Run(wnd); } }
SetLeft,SetTop,SetZIndexは前述のアタッチプロパティを介して各オブジェクトの位置/表示順を指定しています。
これをコンパイルして実行してみます。
-
- で、隠れているボタンを押してみると...
イベントハンドラがそのまま書けるのはとても便利でいいと思います。短い処理で汎用性がなければかなり重宝しそうです。
一応こんな感じでCanpasを利用してオブジェクトを配置出来るのですが、実際にはあまり使わない方法だとか。なんじゃそりゃ...。
スタックパネル
キャンバスの次はスタックパネル。名前からしてスタックのようにしてオブジェクトを管理するパネルでしょうか。
ひとまずスタックパネルでボタンを管理するサンプルを書いてみました。
using System; using System.Windows; using System.Windows.Controls; class Test { [STAThread] public static void Main(){ StackPanel stkpnl1 = new StackPanel(); stkpnl1.Orientation = Orientation.Horizontal; string[] texts = {"ほげほげ1", "もげもげ", "ふがふが3", "フー4", "バー5"}; foreach (string text in texts){ Button btn = new Button(); btn.FontSize = 30; btn.Content = text; btn.Click += (sender, e) => { stkpnl1.Children.Remove(sender as Button); }; stkpnl1.Children.Add(btn); } Window wnd = new Window(); wnd.Content = stkpnl1; Application app = new Application(); app.Run(wnd); } }
押したボタンから消えていきますが、よく考えたらもっとスタックらしいプログラムを書けばよかった...。
ま、いいや。とりあえずこんなことも出来るよってことで。
ドックパネル
ドックパネルは自身の子要素を上下左右に配置するためのパネルです。
using System; using System.Windows; using System.Windows.Controls; class Test { [STAThread] public static void Main(){ DockPanel dkPanel1 = new DockPanel(); Button[] btns = new Button[5]; string[] texts = {"Top", "Bottom", "Left", "Right", "Center"}; Dock[] DockType = {Dock.Top, Dock.Bottom, Dock.Left, Dock.Right}; for (int i = 0 ; i < btns.Length ; i++){ btns[i] = new Button(); btns[i].Content = texts[i]; btns[i].FontSize = 30; if (i == 4) { btns[i].Click += (sender, e) => { dkPanel1.LastChildFill = !dkPanel1.LastChildFill; }; } else { DockPanel.SetDock(btns[i], DockType[i]); } dkPanel1.Children.Add(btns[i]); } Window wnd = new Window(); wnd.Content = dkPanel1; Application app = new Application(); app.Run(wnd); } }
ここで出てきているDockPanel.SetDock()はアタッチプロパティを利用しています。少しずつ見慣れてきたとはいえ、やはりなじめない書き方です。
とりあえず動かして見ます。
これは中央部分のボタン(Centerとテキストが書かれたボタン)のクリックイベントにDockPanelのLastChildFillプロパティをtrue/falseを切り替えるようにしたためです。このプロパティ次第で最後に追加されたCenter用のボタンが空き部分を作るのかどうか挙動が変わります。
このレイアウトは結構使いそうなので(テキストにもよく使うと書いてあります)覚えておいた方がよさそうです。
グリッド
表のようなレイアウトを実現するのがグリッドです。
グリッドで表を表現するためには列と行を設定する必要があります。
大まかな流れは以下のとおりです
using System; using System.Windows; using System.Windows.Controls; class Test { [STAThread] public static void Main(){ string[,] texts = { {"1-1","2-1","3-1"}, {"1-2","2-2","3-2"}, {"1-3","2-3","3-3"} }; Grid grdPnl = new Grid(); for (int i = 0 ; i < texts.GetLength(0) ; i++){ grdPnl.ColumnDefinitions.Add(new ColumnDefinition()); grdPnl.RowDefinitions.Add(new RowDefinition()); for (int j = 0 ; j < texts.GetLength(1) ; j++){ Button btn = new Button(); btn.Content = texts[i,j]; btn.Click += (sender, e) => { MessageBox.Show((sender as Button).Content.ToString()); }; Grid.SetRow(btn,i); Grid.SetColumn(btn,j); grdPnl.Children.Add(btn); } } Window wnd = new Window(); wnd.Content = grdPnl; Application app = new Application(); app.Run(wnd); } }
実行すると3x3のボタンがある画面が表示されます。
ボタンを押すと押したボタンのテキストをメッセージボックスに表示します。
ちなみにここで使用しているMessageBoxクラスは通常のWindowsフォームで使用している名前空間(System.Windows.Forms)ではなく、System.WindowsのMessageBoxクラスです。
次にグリッドの線を変更してみます。
グリッドに線を引くのはGridクラスのShowGridLinesプロパティを使用します。上のソースを少し手直しして再利用します。
using System; using System.Windows; using System.Windows.Controls; class Test { [STAThread] public static void Main(){ string[,] texts = { {"1-1","2-1","3-1"}, {"1-2","2-2","3-2"}, {"1-3","2-3","3-3"} }; Grid grdPnl = new Grid(); Window wnd = new Window(); for (int i = 0 ; i < texts.GetLength(0) ; i++){ grdPnl.ColumnDefinitions.Add(new ColumnDefinition()); grdPnl.RowDefinitions.Add(new RowDefinition()); for (int j = 0 ; j < texts.GetLength(1) ; j++){ Button btn = new Button(); btn.Content = texts[i,j]; btn.Click += (sender, e) => { grdPnl.ShowGridLines = !grdPnl.ShowGridLines ; wnd.Title = (sender as Button).Content.ToString(); }; Grid.SetRow(btn,i); Grid.SetColumn(btn,j); grdPnl.Children.Add(btn); } } wnd.Content = grdPnl; Application app = new Application(); app.Run(wnd); } }
これを実行してみます。
初期表示される画面は修正前のソースで作ったプログラムと一緒です。
で、何かボタンを押してみるとボタンとボタンの間に点線が表示されます。
さらに今回はMessageBoxではなく、WindowのTitleを利用してどのボタンが押されたのかをわかるようにしてみました。
グリッドのまとめとして複数グリッドにまたがったボタンを作って最後にします。
using System; using System.Windows; using System.Windows.Controls; class Test { [STAThread] public static void Main(){ Window wnd = new Window(); Grid grdPnl = new Grid(); grdPnl.ShowGridLines = true; for (int i = 0 ; i < 3 ; i++){ grdPnl.ColumnDefinitions.Add(new ColumnDefinition()); grdPnl.RowDefinitions.Add(new RowDefinition()); } Button btn1 = new Button(); btn1.Content = "1-1...3-1"; Grid.SetRow(btn1,0); Grid.SetColumn(btn1,0); Grid.SetColumnSpan(btn1,3); btn1.Click += (sender, e) => { wnd.Title = (sender as Button).Content.ToString(); grdPnl.ShowGridLines = !grdPnl.ShowGridLines ; }; Button btn2 = new Button(); btn2.Content = "2-2...2-3"; Grid.SetRow(btn2,1); Grid.SetColumn(btn2,1); Grid.SetRowSpan(btn2,2); btn2.Click += (sender, e) => { wnd.Title = (sender as Button).Content.ToString(); grdPnl.ShowGridLines = !grdPnl.ShowGridLines ; }; grdPnl.Children.Add(btn1); grdPnl.Children.Add(btn2); wnd.Content = grdPnl; Application app = new Application(); app.Run(wnd); } }
実行するとたしかに複数グリッドにまたがったボタンのある画面が表示されます。
「2-1...2-3」ボタンを押すとグリッドが消えてタイトルが変わります。
今度は「1-1...3-1」ボタンを押すとグリッドがまた出てきてタイトルが変わります。
複数のグリッドを超えてボタンが設置出来るのは非常に面白いと感じます。
以上で3章はおしまい。
実際に作ってみてやっとWindowsフォームとの違いが何となく感じられるようになってきた感じがします。積み木を作っているようなそんな印象を受けました。
テキストと全く同じものを作っても得るものが少ないと思い、イベントハンドラの追加やMessageBoxを使用してみましたが、このあたりの作りやすさはさすがだと思います。特にイベントハンドラに匿名メソッドを割り当てられるのは便利だと感じています。
多用する機会はなさそうですが、あって悪い機能ではないしそのうち好きになりそうです。
次は4章の描画オブジェクトについてまとめます。