Visual StudioのIDEでWindowsフォームを作ると、System.Windows.Forms.Form
を継承したクラスが作成されます。今回はIDEに頼らないでラムダ式を使ってコーディングしてみます。
ラムダ式によるフォーム生成
private void ShowForm2() {
var form = new Form();
var nextFormButton = new Button();
var closeButton = new Button();
form.Text = "form2";
nextFormButton.Location=new Point(30, 50);
nextFormButton.Text = "次へ";
nextFormButton.Click += (sender, e) => ShowForm3();
closeButton.Location = new Point(120, 50);
closeButton.Text = "閉じる";
closeButton.Click += (sender, e) => form.Close();
form.Controls.Add(nextFormButton);
form.Controls.Add(closeButton);
form.Show();
}
private void ShowForm3() {
var form = new Form();
var textbox1 = new TextBox();
var textbox2 = new TextBox();
var closeButton = new Button();
form.Text = "form3";
textbox1.Location = new Point(10, 10);
textbox1.Leave += (sender, e) => textbox2.Text = textbox1.Text;
//textbox1 = null;
textbox2.Location = new Point(10, 30);
closeButton.Location = new Point(30, 50);
closeButton.Text = "閉じる";
closeButton.Click += (sender, e) => form.Close();
form.Controls.Add(textbox1);
form.Controls.Add(textbox2);
form.Controls.Add(closeButton);
form.Show();
}
ShowForm2
は「次へ」「閉じる」ボタンがついたフォームを作成・表示するメソッドです。次へのボタンでShowForm3
を実行します。ShowForm3
はテキストボックスが2つと「閉じる」ボタンがついたフォームを作成・表示するメソッドです。上側のテキストボックスに文字を入力してTab移動などを行うと、同じ内容が下のテキストボックスにもコピーされます。
このコードの特長は一つのメソッドでフォームの生成とイベントハンドラをすべて記述できていること、また、フォームの作成に伴って新たなクラスを全く必要としていないことです。アプリケーション全体を新たなクラスなしに作ることもできそうな気がします。しかし実際にそのようにすれば設計上いろいろな無理が出てきそうです。フォームを作成する場面ではIDEが使えないこの手法は採用されることはないと思いますが、Adapterなどその他の場面はラムダ式を使って簡潔に記述できる場面もあります。
このように2つのアプローチが存在することとを理解した上で、ラムダ式が向くところ、オブジェクト指向が向くところを適宜選択しながら設計を行うことがこれからの開発スタイルになりそうです。
補足
ラムダ式を使う上での注意点があります。ShowForm3
のtextBox1
のLeave
イベントでtextBox2.Text=textBox1.Text
が実行されます。
この場合のtextBox1
・textBox2
などのラムダ式の外で宣言された変数を自由変数、sender
・e
などのラムダ式の引数となっている変数を束縛変数と呼びます。
これが実行されるのはShowForm3
メソッドが完了してtextBox1
からフォーカスが抜けたときですから、それまでに自由変数textBox1
に別のものを代入すると不正な処理が実行されます。例えばコード中のtextbox1
= null
のコメントを外すとLeave時に例外が発生ます。つまり自由変数は使い回しすることができないのです。特にループ中のラムダ式ではその点に気を付ける必要があります。具体的にはループ内で自由変数を宣言して使います。
自由変数が実際に使用される時点では既に変数スコープを抜けてしまっていますがそれについては内部的に保持されているので問題ありません。