C#備忘ログ
C#でWindowsフォームを使うようなアプリケーションは殆ど書かないのであまり興味もなかったのですが、今回2つのフォームを使うツールを書いたときに困ったことがあった。
フォームA(class FormA : Form) / フォームB(class FormB : Form) の2つがあって、
1)フォームA内に配置したボタン(Button1)をクリックすると、フォームBを生成すると同時にフォームAは非表示へ。
2)フォームBを閉じると、フォームAを表示する。
通常ならたぶん、フォームAの button1の Clickイベントハンドラに フォームBをnewして Show()メソッドをコール。
//子フォームを生成して表示、自身は非表示にする
private void Button1_Click(object sender, EventArgs e)
{
this.Hide();
var formB = new FormB();
formB.Show(this);
}
そしてフォームBを閉じたり、非表示になった時のイベントハンドラ(FormB_FormClosingとかFormB_VisibleChangeとか)でFormAのShow()メソッドをコール。
//親フォームを表示(復帰)
private void Form1_FormClosing(Object sender, FormClosingEventArgs e)
{
this.Owner.Show();
}
のような感じになると思うんですが、フォームBを閉じたときに、フォームAを表示するだけじゃなくて、フォームA上のbutton1のTextプロパティの表示も変えたい!とか、button1のEnabledプロパティーを・・・とか、にしたいとき、FormA側にpublicなメソッドを一個追加してコールさせなければならない・・・。
つまり、フォームAの勝手な都合で、全然関係のないフォームBのソースも修正しなければならなくなる。フォームA,フォームBそれぞれがお互いのインスタンスを共有しなければならない、という非常に非効率な状態になる。2つのフォームだけならまだなんとかなるけど、フォーム10個とかになったときの事を考えると恐ろしい。。。
この場合の解決方法はやはり・・・フォームA側から直接フォームBのイベントに+= 演算子でラムダ式を注入するのが一番いい。Showメソッドで自分自身のインスタンスを渡す必要もない。フォームBのソースを汚染することもなくなる。
ま、ちゃんとメソッドを定義して・・・いう書き方の方がいいのか、インラインでラムダ式を放り込む方がいいのか、書き手側の好みの問題でしょうか。
//FormA
private void Button1_Click(object sender, EventArgs e)
{
this.Hide();
var formB = new FormB();
formB.Show();
//ラムダ式を注入
formB.FormClosing += ( bs, be ) => { Show(); button1.Text = "フォームBは閉じられた!"; };
//デリゲートを追加
formB.FormClosing += formBClosed;
}
private void formBClosed(object sender, FormClosedEventArgs e)
{
Show();
button1.Text = "フォームBは閉じられた!";
}
また、FormBの子コントロールの特定のイベントにイベントハンドラを注入したければ、子コントロールにもフォームA側からイベントハンドラを注入してあげればいいが、フォームの子コントロールのアクセスレベルは private なので、単純に子コントロールへはアクセスできない。
そういうときは、フォームBのControlsプロパティから目的の子コントロールを得られる。
//FormA
private void Button1_Click(object sender, EventArgs e)
{
this.Hide();
var formB = new FormB();
formB.FormClosing += ( bs, be ) => { Show(); };
formB.Show();
var ctrl = formB.Controls["button2"]);
ctrl.Click += (bs,be) => button1.Text = "クリックされたよ";
}
//エラー処理はしていないよ
メインフォーム ⇔ 子フォーム間の依存関係はできるだけ避けたいし、子フォーム間同士の依存関係もできるだけ避けたい。お互いのフォームがお互いのインスタンス(正確にはインスタンスへの参照)を持ってコードを書くとフォームが増えるに従って グチャグチャになってしまう気がする。。。
気をつけよう。