C# 来自面板及其子控件的MouseEnter和MouseLeave事件
我有一个C# 来自面板及其子控件的MouseEnter和MouseLeave事件,c#,.net,winforms,mouseevent,C#,.net,Winforms,Mouseevent,我有一个面板,其中包含子控件 如果我处理面板的MouseEnter和MouseLeave事件,以及其子面板的MouseEnter和MouseLeave事件,则事件按以下顺序引发: Panel.MouseEnter Panel.MouseLeave Child1.MouseEnter Child1.MouseLeave Panel.MouseEnter Panel.MouseLeave 但我需要以下命令: Panel.MouseEnter Child1.MouseEnter Child1.Mou
面板
,其中包含子控件
如果我处理面板的MouseEnter
和MouseLeave
事件,以及其子面板的MouseEnter
和MouseLeave
事件,则事件按以下顺序引发:
Panel.MouseEnter
Panel.MouseLeave
Child1.MouseEnter
Child1.MouseLeave
Panel.MouseEnter
Panel.MouseLeave
但我需要以下命令:
Panel.MouseEnter
Child1.MouseEnter
Child1.MouseLeave
Panel.MouseLeave
有可能吗?我相信有可能。用于验证WinForms应用程序事件的好工具
窗体事件顺序
- 由Urs Eichmann编写的EventSpy创建。()
- 使用.NET Framework 3.5并启用Visual Basic的应用程序框架
鼠标进入子控件时正在“离开”面板,这就是它触发事件的原因
您可以在面板MouseLeave
事件处理程序中沿以下行添加一些内容:
// Check if really leaving the panel
if (Cursor.Position.X < Location.X ||
Cursor.Position.Y < Location.Y ||
Cursor.Position.X > Location.X + Width - 1 ||
Cursor.Position.Y > Location.Y + Height - 1)
{
// Do the panel mouse leave code
}
//检查是否真的离开面板
如果(光标位置X<位置X||
Cursor.Position.YLocation.X+Width-1||
光标.Position.Y>位置.Y+高度-1)
{
//面板鼠标是否留下代码
}
这可能不是最优雅的解决方案,但您可以在父控制面板(子类面板)中设置一个类似“bool selected”的bool值属性。然后,当面板的鼠标指针启动时,将其设置为true…然后停止mouseleave逻辑启动,除非将其设置为false
范例
bool selected;
MouseEnter(..,..)
{
if (!selected)
selected = true;
else
selected = false;
if (selected)
/.. Logic Here ../
}
MouseLeave()
{
if (selected)
return;
/.. Logic Here ../
}
实际上,我只是让孩子的MouseLeave事件设置参数
Example:
Parent:
bool doLeave;
MouseLeave(..,..)
{
if (doLeave)
{
/.. Logic ../
doLeave = false;
}
Child:
MouseLeave(..., ...)
{
DerivedPanel parent = this.Parent as DerivedPanel;
if (parent != null)
parent.doLeave = true;
}
这两种方法都不优雅,但都能奏效。这是一个棘手的问题,很难可靠地编写代码。一个想法是“捕获”列表中的3个传入事件,并在列表完成后执行所需代码(列表中有3个所需事件)。然后,当您执行完任何代码(或者可能以相反的方式捕获事件组合)后,您可以清空列表,并为下一次发生特定组合事件做好准备。不理想,只是一个想法
当然,这并不能解决潜在的解决问题&汉斯提出的可能遗漏的事件。可能需要更多的上下文。如果您不介意创建一个usercontrol(从您希望的面板或其他父容器派生),
重写您父母的OnMouseLeave
方法,如下所示
protected override void OnMouseLeave(EventArgs e)
{
if(this.ClientRectangle.Contains(this.PointToClient(Control.MousePosition)))
return;
else
{
base.OnMouseLeave(e);
}
}
然后,事件引发将按所需顺序进行。解决方案是跟踪进入/离开的次数。
在总体控制中添加一个计数器:
private int mouseEnterCount = 0;
在MouseEnter处理程序中,执行以下操作:
if (++mouseEnterCount == 1)
{
// do whatever needs to be done when it first enters the control.
}
if (--mouseEnterCount == 0)
{
// do whatever needs to be done when it finally leaves the control.
}
在MouseLeave处理程序中,执行以下操作:
if (++mouseEnterCount == 1)
{
// do whatever needs to be done when it first enters the control.
}
if (--mouseEnterCount == 0)
{
// do whatever needs to be done when it finally leaves the control.
}
并对所有子控件以及包含的对象执行上述MouseEnter和MouseLeave事件处理程序。Matthew的答案并不总是有效。尤其是如果子控件设置为其容器的边缘,并且鼠标沿该方向离开控件时。您将永远无法检测到MouseLeave事件
最好的方法是创建一个用户控件容器,然后钩住所有子控件的MouseEnter和MouseLeave事件,以便您可以随时正确地检测鼠标的位置和时间。然后,如果它进入容器的边界,您可以触发自定义MouseEnter事件,当它离开MouseLeave事件时。检查子组件
if (panel1.GetChildAtPoint(panel1.PointToClient(Cursor.Position)) == null)
{
// mouse leave panel and children
}
吉米·T.是对的。如果父控件(面板)边缘和子控件之间没有(或很小)空间,则会出现问题
这就是我在UserControl派生类中解决此问题的方法:
public CSStackPanelItem()
{
InitializeComponent();
MouseEnter += new EventHandler(CSStackPanelItem_MouseEnter);
foreach (Control child in Controls)
{
child.MouseEnter += (s, e) => CSStackPanelItem_MouseEnter(s, e);
child.MouseLeave += (s, e) => OnMouseLeave(e);
}
}
protected override void OnMouseLeave(EventArgs e)
{
if (this.ClientRectangle.Contains(this.PointToClient(Control.MousePosition)))
return; //suppress mouse leave event handling
if (m_bIsHover)
{
m_bIsHover = false;
Invalidate(); //actually my mouse Enter/Leave event
}
base.OnMouseLeave(e);
}
void CSStackPanelItem_MouseEnter(object sender, EventArgs e)
{
m_bIsHover = true;
Invalidate(); //actually my mouse Enter/Leave event
}
我的解决方案是为面板和该面板的父窗体创建一个MouseEnter
事件。我不参与任何鼠标移动事件
当光标进入面板时,MouseEnter
激发。我可以访问所有面板子控件,但什么也没有发生(这正是我想要的)。当我离开面板时,父窗体的MouseEnter
将启动。谢谢,尝试过,但它有错误:存在竞争条件,因为光标。位置
是当前位置,而且不完全是鼠标离开控件时的位置。谢谢和+1让我了解了我的想法:在child MenuDropdown中检测鼠标位置还是不是好主意。但是,如果包含的控件位于边界上,它将无法工作。(对注意到它的用户表示感谢。)不需要创建用户控件。在父控件和子控件的MouseLeave事件中使用了这段代码,效果非常好。