有没有办法检测用户控件外的鼠标点击?

Bil*_*soe 15 c# user-controls mouseevent winforms

我正在创建一个自定义下拉框,我想在下拉框外单击鼠标时进行注册,以便隐藏它.是否可以检测到控件外的点击?或者我应该在包含的表单上制作一些机制,并在任何下拉框打开时检查鼠标点击?

用户控制

Cod*_*ray 13

所以我终于明白,当用户点击它之外时你只想关闭它.在这种情况下,该Leave事件应该可以正常工作...出于某种原因,我得到的印象是,只要他们将鼠标移到您的自定义下拉列表之外,您就希望它关闭.Leave只要您的控件失去焦点,就会引发该事件,如果用户点击其他内容,则当他们点击的内容获得焦点时,它肯定会失去焦点.

文档还说这个事件在必要时在控制链上下移动:

EnterLeave事件是分层的,并会级联上下父链,直到达到适当的控制.例如,假设您有一个带有两个GroupBox控件的Form,并且每个GroupBox控件都有一个TextBox控件.当插入符号从一个TextBox移动到另一个TextBox时,Leave将为TextBox和GroupBox Enter引发事件,并为另一个GroupBox和TextBox引发该事件.

覆盖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();
}
Run Code Online (Sandbox Code Playgroud)

然后出于测试目的,我创建了一个显示下拉UserControl on命令的表单:

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
   }
}
Run Code Online (Sandbox Code Playgroud)

一切都与上面的代码完美配合,除了一件事:如果用户点击表单的空白区域,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);
   }
}
Run Code Online (Sandbox Code Playgroud)

是的,这最后一部分感觉就像一个黑客.正如其他人所提到的,更好的解决方案是使用该SetCapture函数指示Windows在UserControl窗口上捕获鼠标.控件的Capture属性提供了一种更简单的方法来执行相同的操作.