Panel中的MouseEnter和MouseLeave事件及其子控件

我有一个包含子控件的Panel

如果我处理PanelMouseEnterMouseLeave事件及其子项的MouseEnterMouseLeave事件, MouseLeave以下顺序引发事件:

 Panel.MouseEnter Panel.MouseLeave Child1.MouseEnter Child1.MouseLeave Panel.MouseEnter Panel.MouseLeave 

但我需要以下顺序:

 Panel.MouseEnter Child1.MouseEnter Child1.MouseLeave Panel.MouseLeave 

那可能吗?

如果您不介意创建usercontrol(从您希望的面板或其他父容器派生),请覆盖父项的OnMouseLeave方法,如下所示:

 protected override void OnMouseLeave(EventArgs e) { if(this.ClientRectangle.Contains(this.PointToClient(Control.MousePosition))) return; else { base.OnMouseLeave(e); } } 

然后,事件提升将按要求的顺序进行。

当鼠标进入子控件时鼠标“离开”面板,这就是它触发事件的原因。

您可以在面板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 } 

解决方案是跟踪进入/离开的数量。 在你的整体控制中添加一个计数器:

 private int mouseEnterCount = 0; 

在MouseEnter处理程序中执行以下操作:

 if (++mouseEnterCount == 1) { // do whatever needs to be done when it first enters the control. } 

在MouseLeave处理程序中执行以下操作:

 if (--mouseEnterCount == 0) { // do whatever needs to be done when it finally leaves the control. } 

并为所有子控件以及包含对象执行上述MouseEnter和MouseLeave事件处理程序。

马修的答案永远不会奏效。 特别是如果将子控件设置为其容器的边缘并且鼠标在该方向上移出控件。 您永远不会检测到MouseLeave事件。

最好的方法是创建一个用户控件容器,然后挂钩所有子控件的MouseEnter和MouseLeave事件,以便您可以随时正确地检测鼠标的位置和位置。 然后,如果它进入容器的边界,您可以触发自定义MouseEnter事件,并在它离开MouseLeave事件时。

这可能不是最优雅的解决方案,但您可以在父控制面板(子类面板)中设置一个属性,如bool值,如“bool selected”。 然后当面板的MouseEnter触发时将其设置为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; } 

两者都不优雅,但它会起作用。

我相信是这样。 一个很好的工具,用于validation您的WinForms应用程序的事件。

Windows.Forms事件顺序

http://missico.spaces.live.com/blog/cns!7178D2C79BA0A7E3!186.entry

  • 由Urs Eichmann编写的EventSpy创建。 ( ftp://missico.net/EventSpy.zip
  • 使用.NET Framework 3.5并启用Visual Basic的应用程序框架。

这是一个棘手的问题,并且难以可靠地编码。 一个想法是“捕获”列表中的3个传入事件,并在列表完成后执行所需的代码(列表中有3个所需事件)。 然后,当您完成执行任何代码(或者可能反过来捕获事件组合)时,您可以清空列表并准备好下次特定组合事件发生时。 不理想,但只是一个想法。

当然,这并没有克服汉斯提出的潜在解决问题和可能错过的事件。 也许更多的背景是有序的。

检查子组件..

 if (panel1.GetChildAtPoint(panel1.PointToClient(Cursor.Position)) == null) { // mouse leave panel and children } 

Jimmy 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 }