有什么方法可以检测用户控件外部的鼠标单击?

问题描述 投票:15回答:6

我正在创建一个自定义下拉框,我想在鼠标单击下拉框外时进行注册以隐藏它。是否可以检测控件外部的单击?还是应该在包含表单上建立某种机制并在打开任何下拉框时检查mouseclick?

“用户控件”

c# winforms user-controls mouseevent
6个回答
13
投票

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

文档还说,此事件在必要时在控制链中向上和向下级联:

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

覆盖UserControl的Enter方法是处理此问题的最佳方法:

OnLeave

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

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

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

一切都与上面的代码完美配合,except一件事:如果用户单击表单的空白区域,则UserControl不会关闭。嗯,为什么不呢?好吧,因为表单本身不需要焦点。只有controls可以获取焦点,而我们没有单击控件。而且因为没有其他东西偷走焦点,所以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 } } 事件再也没有引发过,这意味着UserControl不知道它应该自己关闭。

如果用户在单击表单的空白区域时需要UserControl自行关闭,则需要对此进行一些特殊处理。因为您说的是只关心clicks,所以您可以只处理表单的Leave事件,并将焦点设置到另一个控件:

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); } } 指示Windows将鼠标捕获到UserControl窗口上方。控件的SetCapture function提供了更简单的方法来执行相同的操作。


2
投票

技术上,您需要p /调用SetCapture才能接收控件之外发生的点击事件。

但是在您的情况下,按照@Martin的建议处理Capture property事件就足够了。

EDIT:在寻找Capture的用法示例时,我遇到了SetCapture()属性,但我不知道该属性。使用该属性意味着您无需p /调用任何东西,这在我的书中总是一件好事。

因此,在显示下拉菜单时,必须将Leave设置为SetCapture(),然后确定鼠标指针是否位于click事件处理程序中的控件内,如果不是,请将Control.Capture设置为Capture,然后关闭下拉菜单。


2
投票

处理表单的true事件,或覆盖表单的Capture方法:

false

然后:

MouseDown

旧的OnMouseDown包含方法可用于指示是否一个点包含在一个矩形内。控件的“边界”属性为由控件边缘定义的外部enter code here 。那个地点protected override void OnMouseDown(MouseEventArgs e) { if (!theListBox.Bounds.Contains(e.Location)) { theListBox.Visible = false; } } 的属性是相对于控件的点收到了System.Drawing.Rectangle事件。窗体中控件的Bounds属性是相对于表格。


0
投票

您可能正在寻找请假事件:

Rectangle

当输入焦点离开控件时发生离开。


0
投票

我只是想分享这个。这样做可能不是一个好方法,但是看起来它适用于在假的“ MouseLeave”上关闭的下拉面板,我试图将其隐藏在Panel MouseLeave上,但由于从面板移至按钮而无法工作面板,因为按钮不是面板本身。也许有更好的方法可以做到这一点,但是我分享了这一点,因为我花了大约7个小时来弄清楚如何使其工作。感谢@FTheGodfather

但是它仅在鼠标在表单上移动时有效。如果有面板,则将无法使用。

MouseEventArgs

-1
投票

我自己做的,这就是我做的。

当下拉列表打开时,在控件的父窗体上注册一个click事件:

MouseDown

但是这只花了一半。您可能希望在停用当前窗口时也关闭下拉菜单。对我而言,最可靠的检测方法是通过计时器检查当前哪个窗口处于活动状态:

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

    private void click_to_show_Panel_button_MouseDown(object sender, MouseEventArgs e)
    {
        item_panel1.Visible = true; //Menu Panel
    }



    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        if (!item_panel1.Bounds.Contains(e.Location))
        {
            item_panel1.Visible = false; // Menu panel 
        }
    }

当然,只有在下拉列表可见时,您才应让计时器运行。另外,打开下拉列表时,您希望在父表单上注册其他事件:

this.Form.Click += new EventHandler(CloseDropDown);

请不要忘记在CloseDropDown方法中注销所有这些事件:)

编辑:

我忘记了,您还应该在控件上注册Leave事件,以查看是否激活/单击了另一个控件:

[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();

我想我已经明白了,应该涵盖所有基础。让我知道我是否缺少任何东西。

© www.soinside.com 2019 - 2024. All rights reserved.