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 = "クリックされたよ"; } //エラー処理はしていないよ
メインフォーム ⇔ 子フォーム間の依存関係はできるだけ避けたいし、子フォーム間同士の依存関係もできるだけ避けたい。お互いのフォームがお互いのインスタンス(正確にはインスタンスへの参照)を持ってコードを書くとフォームが増えるに従って グチャグチャになってしまう気がする。。。
気をつけよう。