Winforms:首先在主窗体上拦截鼠标事件,而不是在控件上

肯定有一种方便的方法:

我在主窗体上实现了鼠标拖动行为的“移动窗口”,
我希望鼠标单击/移动事件被表单拦截,而不是由其中的控件拦截。

我想找到一个等效/复制鼠标事件的“KeyPreview”属性

此外,我想避免在12个控件的鼠标事件中单独将鼠标事件重定向到主窗体方法12次(这是我到目前为止找到的丑陋的解决方法)

有任何想法吗 ?

订阅所有控件MouseMove事件(考虑对嵌套控件进行递归操作)

foreach (Control control in Controls) control.MouseMove += RedirectMouseMove; 

并在此事件处理程序中引发MouseMove

 private void RedirectMouseMove(object sender, MouseEventArgs e) { Control control = (Control)sender; Point screenPoint = control.PointToScreen(new Point(eX, eY)); Point formPoint = PointToClient(screenPoint); MouseEventArgs args = new MouseEventArgs(e.Button, e.Clicks, formPoint.X, formPoint.Y, e.Delta); OnMouseMove(args); } 

请记住,控件接收具有本地控制坐标的MouseEvents。 所以你需要将它转换为表格坐标。 嵌套控件可能有缺点,但我留给你(例如调用Parent.PointToClient)

更新 :您仍然可以处理控制事件 – 只需再次订阅事件。

您可以使用全局鼠标钩来拦截鼠标事件, MSDN上有一个示例

根据您的意见,

在基类中实现鼠标事件的重定向function,然后使所有控件从该基类派生。

因此,您只需实现一次该function,然后您的所有控件将“重新抛出”主要表单捕获的鼠标事件。

希望这可以帮助。

重写Control.PreProcessMessage方法:

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.preprocessmessage.aspx

编辑:

看起来PreProcessMessage可能不适用于鼠标事件。 尝试重写WndPrc。 它可以肯定拦截鼠标消息,但您需要查看它是否按您想要的顺序拦截它们:

http://bytes.com/topic/c-sharp/answers/752144-preprocessmessage

您可以使用GlobalMouseKeyHook库轻松拦截系统范围的鼠标位置。

在鼠标单击时,您应检查鼠标位置点是否与您的表单相交或者鼠标下的窗口是否为您的表单。

要做后一件事,你需要WindowFromPoint API函数:

  [DllImport( "user32.dll", SetLastError = true )] public static extern IntPtr WindowFromPoint( [In] POINTAPI Point ); private void _mouseListener_MouseClick( object sender, MouseEventArgs e ) { var localPoint = this.PointToClient( e.Location ); bool containsPoint = this.ClientRectangle.Contains( localPoint ); var windowHandle = WindowFromPoint( e.Location ); var ctl = (Form)Form.FromHandle( windowHandle ); bool mainFormClicked = ctl != null && ctl.Handle == this.Handle; if( containsPoint && mainFormClicked ) { //form click is intercepted! } } 

实际上,当我想截取我的表单外的点击时,我会使用这个(没有别的办法)。 在你的情况下,为了性能,我会绑定到每个控件的MouseClick(全局钩子很重)。