控件中的多个MouseHover事件

我正在尝试在C#中实现自定义控件,我需要在鼠标hover时获取事件。 我知道有MouseHover事件但它只触发一次。 为了让它再次发射,我需要使用控件的鼠标并再次输入它。

有什么方法可以做到这一点吗?

让我们将“停止移动”定义为“保持在n ms的x像素半径内”。

订阅MouseMove事件并使用计时器(设置为n ms)来设置超时。 每次鼠标移动时,请检查公差。 如果超出您的容差范围,请重置计时器并记录新的原点。

伪代码:

 Point lastPoint; const float tolerance = 5.0; //you might want to replace this with event subscribe/unsubscribe instead bool listening = false; void OnMouseOver() { lastpoint = Mouse.Location; timer.Start(); listening = true; //listen to MouseMove events } void OnMouseLeave() { timer.Stop(); listening = false; //stop listening } void OnMouseMove() { if(listening) { if(Math.abs(Mouse.Location - lastPoint) > tolerance) { //mouse moved beyond tolerance - reset timer timer.Reset(); lastPoint = Mouse.Location; } } } void timer_Tick(object sender, EventArgs e) { //mouse "stopped moving" } 

我意识到这是一个古老的话题,但我想分享一种我发现的方法:在鼠标移动事件中,在捕获事件的控件上调用ResetMouseEventArgs()。

为什么不在MouseHover事件中订阅MouseMove事件,然后在MouseLeave事件中取消订阅

编辑:

确定鼠标是否停止的一种方法是每次获得鼠标移动事件时启动计时器,当计时器结束时,您可以考虑停止鼠标。 在MouseLeave上删除MouseMove事件的原因允许您仅在鼠标hover在控件上时接收事件。

这是我能想到的最干净的实现。 它工作得很好:

  [DllImport("user32.dll")] static extern IntPtr SendMessage ( IntPtr controlHandle, uint message, IntPtr param1, IntPtr param2 ); const uint WM_MOUSELEAVE = 0x02A3; Point lastMousePoint = Point.Empty; void richTextBox_MouseMove(object sender, MouseEventArgs e) { if (Math.Abs(e.Location.X - lastMousePoint.X) > 1 || Math.Abs(e.Location.Y - lastMousePoint.Y) > 1) { lastMousePoint = e.Location; SendMessage((sender as RichTextBox).Handle, WM_MOUSELEAVE, IntPtr.Zero, IntPtr.Zero); } } void richTextBox_MouseHover(object sender, EventArgs e) { foo(); } 

这是一个稍微简单的版本,不依赖于Timer。 只需记录上次鼠标移动的时间,然后在想要检查鼠标是否hover时比较当前时间。

  private DateTime mouseMoveTime = DateTime.Now; private Point mouseMoveLoc = new Point(); private bool IsHovering() { return (mouseMoveTime.AddMilliseconds(SystemInformation.MouseHoverTime)).CompareTo(DateTime.Now) < 0; } private void myControl_MouseMove(object sender, MouseEventArgs e) { // update mouse position and time of last move if (Math.Abs(eX - mouseMoveLoc.X) > SystemInformation.MouseHoverSize.Width || Math.Abs(eY - mouseMoveLoc.Y) > SystemInformation.MouseHoverSize.Height) { mouseMoveLoc = new Point(eX, eY); mouseMoveTime = DateTime.Now; } } 

或者是一个没有距离容差的真正的短版本。

  private DateTime mouseMoveTime = DateTime.Now; private bool IsHovering() { return (mouseMoveTime.AddMilliseconds(SystemInformation.MouseHoverTime)).CompareTo(DateTime.Now) < 0; } private void myControl_MouseMove(object sender, MouseEventArgs e) { mouseMoveTime = DateTime.Now; } 

只需使用if(IsHovering())...当你需要检查鼠标是否在移动时。

我注意到的一件事是拖动时不会触发MouseMove。 但是,您可以将mouseMoveTime / Loc更新代码复制到拖动事件以绕过此事件。