C# Winforms:首先在主窗体上拦截鼠标事件,而不是在控件上
当然有一种方便的方法可以做到这一点:C# Winforms:首先在主窗体上拦截鼠标事件,而不是在控件上,c#,winforms,C#,Winforms,当然有一种方便的方法可以做到这一点: 我已经在我的主窗体上实现了一个鼠标拖动行为的“移动窗口”,我希望鼠标单击/移动事件被窗体拦截,而不是被窗体中的控件拦截 我想为鼠标事件找到一个与“KeyPreview”属性等效的/复制的属性 此外,我希望避免在12个控件的鼠标事件中12次将鼠标事件重定向到主窗体方法(这是迄今为止我发现的最糟糕的解决方法) 有什么想法吗?根据你的评论 在基类中实现鼠标事件的重定向功能,然后使所有控件都派生自该基类 因此,您只需实现一次功能,然后所有控件都将“重新播放”主窗体捕
我已经在我的主窗体上实现了一个鼠标拖动行为的“移动窗口”
,我希望鼠标单击/移动事件被窗体拦截,而不是被窗体中的控件拦截 我想为鼠标事件找到一个与“KeyPreview”属性等效的/复制的属性 此外,我希望避免在12个控件的鼠标事件中12次将鼠标事件重定向到主窗体方法(这是迄今为止我发现的最糟糕的解决方法)
有什么想法吗?根据你的评论 在基类中实现鼠标事件的重定向功能,然后使所有控件都派生自该基类 因此,您只需实现一次功能,然后所有控件都将“重新播放”主窗体捕获的鼠标事件
希望这有帮助。订阅所有控件MouseMove事件(考虑对嵌套控件递归执行此操作) 并在此事件处理程序中引发MouseMove
private void RedirectMouseMove(object sender, MouseEventArgs e)
{
Control control = (Control)sender;
Point screenPoint = control.PointToScreen(new Point(e.X, e.Y));
Point formPoint = PointToClient(screenPoint);
MouseEventArgs args = new MouseEventArgs(e.Button, e.Clicks,
formPoint.X, formPoint.Y, e.Delta);
OnMouseMove(args);
}
请记住,控件接收带有控件本地坐标的MouseEvents。所以你需要把它转换成形式坐标。
嵌套控件可能有缺点,但我将其留给您(例如,调用Parent.PointToClient)
更新:您仍将能够处理控制事件-只需再订阅一次事件。您可以使用全局鼠标挂钩拦截鼠标事件,有一个覆盖控制。预处理消息方法: 编辑: 似乎预处理消息可能不适用于鼠标事件。尝试覆盖WndPrc。它确实可以拦截鼠标消息,但您需要查看它是否按照您想要的顺序拦截鼠标消息: 您可以使用轻松拦截系统范围的鼠标位置 单击鼠标后,您应该检查鼠标位置点是否与窗体相交,或者鼠标下的窗口是否为窗体。 要执行后一项操作,需要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!
}
}
实际上,当我想截取表单外部的点击时,我会使用它(没有其他方法)。在您的例子中,为了性能起见,我会绑定到每个控件的鼠标单击(全局钩子很重)。子控件是否也处理鼠标单击/移动事件?其中一些,而不是全部。我当然希望避免在12个控件中将鼠标事件重定向到主窗体方法12次,您可以使用。(琐碎的回答自动转换成评论。)是的,我确实想到了。。。但这让我对遗留代码的更改超出了我的意愿。我只是想知道是否有一种方法可以完全绕过控件…正如在另一篇评论中所述,我想知道是否有一种方法可以完全绕过控件…但KeyPreview的工作方式几乎相同(事件参数的处理属性除外)-它绕过控件并首先在表单级别处理事件。我在哪里做?在主窗体上?那会绕过控制吗?
[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!
}
}