我正在创建一个自定义下拉框,我想在鼠标单击下拉框外时进行注册以隐藏它。是否可以检测控件外部的单击?还是应该在包含表单上建立某种机制并在打开任何下拉框时检查mouseclick?
所以我终于明白,您只希望当用户clicks在其外部时关闭它。在这种情况下,Leave
event应该可以正常工作...由于某种原因,我给您的印象是,只要他们将鼠标移到自定义下拉列表之外,它就应该关闭。每当您的控件失去焦点时,都会引发Leave
事件,并且如果用户单击其他内容,则肯定会失去焦点,因为他们单击的内容会获得焦点。
文档还说,此事件在必要时在控制链中向上和向下级联:
Leave
和Enter
事件是分层的,将在父链上级联,直到达到适当的控制为止。例如,假设您有一个带有两个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提供了更简单的方法来执行相同的操作。
技术上,您需要p /调用SetCapture
才能接收控件之外发生的点击事件。
但是在您的情况下,按照@Martin的建议处理Capture
property事件就足够了。
EDIT:在寻找Capture
的用法示例时,我遇到了SetCapture()属性,但我不知道该属性。使用该属性意味着您无需p /调用任何东西,这在我的书中总是一件好事。
因此,在显示下拉菜单时,必须将Leave设置为SetCapture()
,然后确定鼠标指针是否位于click事件处理程序中的控件内,如果不是,请将Control.Capture设置为Capture
,然后关闭下拉菜单。
处理表单的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属性是相对于表格。
您可能正在寻找请假事件:
Rectangle
当输入焦点离开控件时发生离开。
我只是想分享这个。这样做可能不是一个好方法,但是看起来它适用于在假的“ MouseLeave”上关闭的下拉面板,我试图将其隐藏在Panel MouseLeave上,但由于从面板移至按钮而无法工作面板,因为按钮不是面板本身。也许有更好的方法可以做到这一点,但是我分享了这一点,因为我花了大约7个小时来弄清楚如何使其工作。感谢@FTheGodfather
但是它仅在鼠标在表单上移动时有效。如果有面板,则将无法使用。
MouseEventArgs
我自己做的,这就是我做的。
当下拉列表打开时,在控件的父窗体上注册一个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();
我想我已经明白了,应该涵盖所有基础。让我知道我是否缺少任何东西。