web-dev-qa-db-ja.com

ユーザーコントロールの外でマウスクリックを検出する方法はありますか?

カスタムドロップダウンボックスを作成していますが、ドロップダウンボックスの外側でマウスがクリックされたときに、それを非表示にするために登録したいと思います。コントロールの外側のクリックを検出することは可能ですか?または、含まれているフォームに何らかのメカニズムを作成し、ドロップダウンボックスが開いているときにマウスクリックを確認する必要がありますか?

user control

15
Bildsoe

ですから、ユーザーがその外側をクリックした場合にのみ閉じたいと最終的に理解しました。その場合、 Leave event は問題なく機能するはずです...何らかの理由で、カスタムドロップダウンの外にマウスを移動するたびに閉じたいという印象を受けました。 Leaveイベントは、コントロールがフォーカスを失うたびに発生します。ユーザーが他の何かをクリックすると、クリックしたものがフォーカスを獲得するため、確実にフォーカスが失われます。

ドキュメントには、このイベントが必要に応じて制御チェーンを上下にカスケードすることも記載されています。

EnterイベントとLeaveイベントは階層的であり、適切な制御に到達するまで親チェーンを上下にカスケードします。たとえば、2つのGroupBoxコントロールを持つフォームがあり、各GroupBoxコントロールに1つのTextBoxコントロールがあるとします。キャレットが1つのTextBoxから別のTextBoxに移動されると、TextBoxとGroupBoxに対してLeaveイベントが発生し、他のGroupBoxとTextBoxに対してEnterイベントが発生します。

UserControlのOnLeaveメソッドをオーバーライドすることが、これを処理するための最良の方法です。

protected override void OnLeave(EventArgs e)
{
   // Call the base class
   base.OnLeave(e);

   // When this control loses the focus, close it
   this.Hide();
}

次に、テストの目的で、コマンドのドロップダウンUserControlを表示するフォームを作成しました。

public partial class Form1 : Form
{
   private UserControl1 customDropDown;

   public Form1()
   {
      InitializeComponent();

      // Create the user control
      customDropDown = new UserControl1();

      // Add it to the form's Controls collection
      Controls.Add(customDropDown);
      customDropDown.Hide();
   }

   private void button1_Click(object sender, EventArgs e)
   {         
      // Display the user control
      customDropDown.Show();
      customDropDown.BringToFront();   // display in front of other controls
      customDropDown.Select();         // make sure it gets the focus
   }
}

上記のコードexceptですべてが完全に機能します。ただし、ユーザーがフォームの空白の領域をクリックしても、UserControlは閉じません。うーん、どうして?ええと、フォーム自体はフォーカスを望まないからです。 コントロールのみがフォーカスを取得でき、コントロールをクリックしませんでした。そして、他に何もフォーカスを盗んだことがないため、Leaveイベントが発生することはありませんでした。つまり、UserControlは、それ自体が閉じることになっていることを知りませんでした。

ユーザーがフォームの空白の領域をクリックしたときにUserControlを閉じる必要がある場合は、そのための特別なケース処理が必要です。 クリックだけが気になると言っているので、フォームのClickイベントを処理して、フォーカスを設定するだけです。別のコントロールに:

protected override void OnClick(EventArgs e)
{
   // Call the base class
   base.OnClick(e);

   // See if our custom drop-down is visible
   if (customDropDown.Visible)
   {
      // Set the focus to a different control on the form,
      // which will force the drop-down to close
      this.SelectNextControl(customDropDown, true, true, true, true);
   }
}

はい、この最後の部分はハックのように感じます。他の人が言及しているように、より良い解決策は、 SetCapture function を使用して、UserControlのウィンドウ上でマウスをキャプチャするようにWindowsに指示することです。コントロールの Capture property は、同じことを行うさらに簡単な方法を提供します。

13
Cody Gray

技術的には、制御外で発生するクリックイベントを受信するには、p/invoke SetCapture() である必要があります。

しかし、あなたの場合、@ Martinが示唆するように、 Leave イベントを処理するだけで十分です。

EDIT:SetCapture()の使用例を探しているときに、 Control.Capture プロパティに出くわしました、私は気づいていませんでした。そのプロパティを使用すると、何もp/invokeする必要がなくなります。これは、私の本では常に良いことです。

したがって、ドロップダウンを表示するときにCapturetrueに設定し、マウスポインタがクリックイベントハンドラのコントロール内にあるかどうかを判断し、そうでない場合は設定する必要があります。 Captureからfalseに移動し、ドロップダウンを閉じます。

2

フォームのMouseDownイベントを処理するか、フォームのOnMouseDownメソッドをオーバーライドします。

enter code here

その後:

protected override void OnMouseDown(MouseEventArgs e)
{

    if (!theListBox.Bounds.Contains(e.Location)) 
    {
        theListBox.Visible = false;
    }
}

含むメソッドoldSystem.Drawing.Rectangleは、点が長方形の中に含まれているかどうかを示すために使用できます。コントロールのBoundsプロパティは、コントロールのエッジによって定義される外側のRectangleです。 MouseEventArgsのLocationプロパティは、MouseDownイベントを受信したコントロールに関連するポイントです。フォーム内のコントロールのBoundsプロパティは、フォームに関連しています。

2
FTheGodfather

あなたはおそらく休暇イベントを探しています:

http://msdn.Microsoft.com/en-us/library/system.windows.forms.control.leave.aspx

離脱は、入力フォーカスがコントロールを離れるときに発生します。

0
Martin