none
「特定の領域の外をクリックした」などのイベントを制御したい RRS feed

  • 質問

  • いつもお世話になってます。
    VS2010、.NET Framework 2.0(C#) でWindowsフォームアプリケーションを開発しています。

    ドロップダウンメニューやツールチップのように、特定の領域(Buttonとか)をクリックすると、
    いくつかのコントロールを含んだ別の領域(Panel)が表示されるモノを作ろうとしています。
    通常、こういったUIは、関係無い部分をクリックすると非表示状態に戻りますが、
    Windowsフォームでこの動作を実現するにはどうしたらいいのでしょうか。

    現状、フォーム内に配置した全てのコントロールにクリックイベントを設定して、
    そこで表示をリセットする方法しか浮かばないのですが、
    コントロールの数だけ同じ処理を書くことになるので気持ち悪いです・・・
    他にもっとスマートな方法は無いのでしょうか。
    2012年3月7日 7:39

回答

  • いずれにしてもクリックされたことを感知しなければならないので、Clickイベントのハンドラを書かなければなりません。とっていもそれぞれのコントロールに手動でイベントハンドラを割り付けるのは大変ですから、フォームのControlsプロパティで得られるコントロール群をループしながら、動的にイベントハンドラを結びつけてやれば良いと思います。

    (参考)
    Windowsフォーム上のコントロールを検索するには?
    http://www.atmarkit.co.jp/fdotnet/dotnettips/479ctrlfind/ctrlfind.html

    #余談かもしれませんが、WPFはルーティングイベントによってこの辺りが解決されます。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク femp 2012年3月7日 9:24
    2012年3月7日 8:32
    モデレータ
  • コンボボックスやツールチップは「他がクリックされる」ではなくフォーカスが外れることで閉じたり消えたりしています。

    該当のコントロールも Leave イベントのハンドラー内で閉じることで仕様を実現できませんか?

    それと、同じ事をする場合はイベントハンドラーは一つで大丈夫です。

    一つのイベントハンドラーを複数のコントロールの Click イベントに割り当てることができます。

    button1.Click += Button_Click;
    button2.Click += Button_Click;
    button3.Click += Button_Click;
    void Button_Click(object sender, EventArgs e) { MessageBox.Show(((Button)sender).Text + "が押された!"); }

    • 回答としてマーク femp 2012年3月7日 9:24
    2012年3月7日 8:40

すべての返信

  • いずれにしてもクリックされたことを感知しなければならないので、Clickイベントのハンドラを書かなければなりません。とっていもそれぞれのコントロールに手動でイベントハンドラを割り付けるのは大変ですから、フォームのControlsプロパティで得られるコントロール群をループしながら、動的にイベントハンドラを結びつけてやれば良いと思います。

    (参考)
    Windowsフォーム上のコントロールを検索するには?
    http://www.atmarkit.co.jp/fdotnet/dotnettips/479ctrlfind/ctrlfind.html

    #余談かもしれませんが、WPFはルーティングイベントによってこの辺りが解決されます。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク femp 2012年3月7日 9:24
    2012年3月7日 8:32
    モデレータ
  • コンボボックスやツールチップは「他がクリックされる」ではなくフォーカスが外れることで閉じたり消えたりしています。

    該当のコントロールも Leave イベントのハンドラー内で閉じることで仕様を実現できませんか?

    それと、同じ事をする場合はイベントハンドラーは一つで大丈夫です。

    一つのイベントハンドラーを複数のコントロールの Click イベントに割り当てることができます。

    button1.Click += Button_Click;
    button2.Click += Button_Click;
    button3.Click += Button_Click;
    void Button_Click(object sender, EventArgs e) { MessageBox.Show(((Button)sender).Text + "が押された!"); }

    • 回答としてマーク femp 2012年3月7日 9:24
    2012年3月7日 8:40
  • 回答ありがとうございます。

    to: trapemiya様
    そうでした、動的にコントロールを取り出せることをすっかり忘れていました。
    これならソースコードもすっきりしますね。
    ありがとうございました。

    to: galaco様
    おお、Leaveイベントで捕まえることが出来ればこれが一番良さそうです。
    ちょっと工夫の必要がありそうですが・・・試してみます。
    ダメだったら、確実にいけそうなtrapemiya様の案でいこうと思います。

    大変助かりました。
    ありがとうございました。
    • 編集済み femp 2012年3月7日 9:28
    2012年3月7日 9:24
  • 試してみた結果を少し報告します。

    Leaveイベントで制御する方法だと、「クリックでフォーカスされないコントロール」をクリックしても
    反応しないという問題?があることに、試してみてから気付きました。
    どこをクリックしても反応させたければ、やはりtrapemiya様の案が必要になるんですね。

    これが問題かどうかは作るアプリの仕様によるのでしょうが、
    とりあえず今回はLeaveイベント方式で進めようと思います。
    改めてありがとうございました。
    2012年3月7日 9:44