UserControl:如何添加MouseWheel Listener?

我正在创建一个UserControl,如果鼠标在控件上并且MouseWheel被旋转,它应该做出反应。

目前我正在这样做,如下所示:

public MyUserControl() { this.MouseWheel += new MouseEventHandler(MouseWheelHandler); } private void MouseWheelHandler(object sender, System.Windows.Forms.MouseEventArgs e) { if (e.Delta > 0) incIndex(); if (e.Delta < 0) decIndex(); } protected override void OnMouseEnter(EventArgs e) { this.Focus(); base.OnMouseEnter(e); } 

事实上这很好,但问题是“this.Focus();”的部分。 因为它破坏了我的表单/应用程序行为。

是否有更好的方法来实现这一目标?

遇到同样的问题,我终于实现了@Paul_Westcott和@ nr1的两种解决方案的混合。 这是@Paul_Westcott解决方案的本地解决方案(仅适用于订阅的winforms控件)。 它是多显示器安全和MDI安全(由应用程序内的其他窗口重叠)

 public static class MouseWheelHandlerForWinformsControl { private class MouseWheelMessageFilter : IMessageFilter { [DllImport("user32.dll")] private static extern IntPtr WindowFromPoint(Point pt); private readonly Control mCtrl; private readonly Action mOnMouseWheel; public MouseWheelMessageFilter(Control ctrl, Action onMouseWheel) { mCtrl = ctrl; mOnMouseWheel = onMouseWheel; } public bool PreFilterMessage(ref Message m) { // handle only mouse wheel messages if (m.Msg != 0x20a) return false; Point mouseAbsolutePosition = new Point(m.LParam.ToInt32()); Point mouseRelativePosition = mCtrl.PointToClient(mouseAbsolutePosition); IntPtr hControlUnderMouse = WindowFromPoint(mouseAbsolutePosition); Control controlUnderMouse = Control.FromHandle(hControlUnderMouse); if (controlUnderMouse != mCtrl) return false; MouseButtons buttons = GetMouseButtons(m.WParam.ToInt32()); int delta = m.WParam.ToInt32() >> 16; var e = new MouseEventArgs(buttons, 0, mouseRelativePosition.X, mouseRelativePosition.Y, delta); mOnMouseWheel(e); return true; } private static MouseButtons GetMouseButtons(int wParam) { MouseButtons buttons = MouseButtons.None; if(HasFlag(wParam, 0x0001)) buttons |= MouseButtons.Left; if(HasFlag(wParam, 0x0010)) buttons |= MouseButtons.Middle; if(HasFlag(wParam, 0x0002)) buttons |= MouseButtons.Right; if(HasFlag(wParam, 0x0020)) buttons |= MouseButtons.XButton1; if(HasFlag(wParam, 0x0040)) buttons |= MouseButtons.XButton2; return buttons; } private static bool HasFlag(int input, int flag) { return (input & flag) == flag; } } public static void MemorySafeAdd(Control ctrl, Action onMouseWheel) { if (ctrl == null || onMouseWheel == null) throw new ArgumentNullException(); var filter = new MouseWheelMessageFilter(ctrl, onMouseWheel); Application.AddMessageFilter(filter); ctrl.Disposed += (s, e) => Application.RemoveMessageFilter(filter); } } 

将此帮助程序类添加到解决方案后,您将控件myControl订阅到鼠标滚轮,在一行中,如下所示:

 public void Init() { MouseWheelHandlerForWinformsControl.MemorySafeAdd(myControl, OnMouseWheelEvent); } void OnMouseWheelEvent(MouseEventArgs args) { // do what you need here } 

复制粘贴自http://social.msdn.microsoft.com/forums/en-US/winforms/thread/eb922ed2-1036-41ca-bd15-49daed7b637c/

 using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using System.Runtime.InteropServices; namespace WindowsApplication1 { public partial class Form1 : Form, IMessageFilter { public Form1() { InitializeComponent(); Application.AddMessageFilter(this); } public bool PreFilterMessage(ref Message m) { if (m.Msg == 0x20a) { // WM_MOUSEWHEEL, find the control at screen position m.LParam Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16); IntPtr hWnd = WindowFromPoint(pos); if (hWnd != IntPtr.Zero && hWnd != m.HWnd && Control.FromHandle(hWnd) != null) { SendMessage(hWnd, m.Msg, m.WParam, m.LParam); return true; } } return false; } // P/Invoke declarations [DllImport("user32.dll")] private static extern IntPtr WindowFromPoint(Point pt); [DllImport("user32.dll")] private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); } } 

这很好用,汉斯帕斯特

只是对已经发布的解决方案稍有不同,以便不必使用P / Invoke。

 public static class MouseWheelHandler { public static void Add(Control ctrl, Action onMouseWheel) { if (ctrl == null || onMouseWheel == null) throw new ArgumentNullException(); var filter = new MouseWheelMessageFilter(ctrl, onMouseWheel); Application.AddMessageFilter(filter); ctrl.Disposed += (s, e) => Application.RemoveMessageFilter(filter); } class MouseWheelMessageFilter : IMessageFilter { private readonly Control _ctrl; private readonly Action _onMouseWheel; public MouseWheelMessageFilter(Control ctrl, Action onMouseWheel) { _ctrl = ctrl; _onMouseWheel = onMouseWheel; } public bool PreFilterMessage(ref Message m) { var parent = _ctrl.Parent; if (parent != null && m.Msg == 0x20a) // WM_MOUSEWHEEL, find the control at screen position m.LParam { var pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16); var clientPos = _ctrl.PointToClient(pos); if (_ctrl.ClientRectangle.Contains(clientPos) && ReferenceEquals(_ctrl, parent.GetChildAtPoint(parent.PointToClient(pos)))) { var wParam = m.WParam.ToInt32(); Func getButton = (flag, button) => ((wParam & flag) == flag) ? button : MouseButtons.None; var buttons = getButton(wParam & 0x0001, MouseButtons.Left) | getButton(wParam & 0x0010, MouseButtons.Middle) | getButton(wParam & 0x0002, MouseButtons.Right) | getButton(wParam & 0x0020, MouseButtons.XButton1) | getButton(wParam & 0x0040, MouseButtons.XButton2) ; // Not matching for these /*MK_SHIFT=0x0004;MK_CONTROL=0x0008*/ var delta = wParam >> 16; var e = new MouseEventArgs(buttons, 0, clientPos.X, clientPos.Y, delta); _onMouseWheel(e); return true; } } return false; } } } 

然后这可以从个别控件中使用

 class MyControl : Control { public MyControl() { ... MouseWheelHandler.Add(this, MyOnMouseWheel); } void MyOnMouseWheel(MouseEventArgs e) { ... } } 

使用FlowLayoutPanel时,Paul Westcott的答案非常有用。 我对MyOnMouseWheel事件的实现是:

 void MyOnMouseWheel(MouseEventArgs e) { int ChangeIncrement = (this.panel1.VerticalScroll.SmallChange * 4); //Change the 4 to any positive number to scroll more or less one each scroll event. if (e.Delta < 0) { int NewValue = this.panel1.VerticalScroll.Value + ChangeIncrement; if (NewValue > this.panel1.VerticalScroll.Maximum) { this.panel1.VerticalScroll.Value = this.panel1.VerticalScroll.Maximum; } else { this.panel1.VerticalScroll.Value = NewValue; } } else if (e.Delta > 0) { int NewValue = this.panel1.VerticalScroll.Value - ChangeIncrement; if (NewValue < this.panel1.VerticalScroll.Minimum) { this.panel1.VerticalScroll.Value = this.panel1.VerticalScroll.Minimum; } else { this.panel1.VerticalScroll.Value = NewValue; } } this.panel1.PerformLayout(); }