C# 如何在子控件下捕获鼠标移动事件

C# 如何在子控件下捕获鼠标移动事件,c#,winforms,events,handle,mousemove,C#,Winforms,Events,Handle,Mousemove,我正在尝试处理一个特定窗体上的mouseclick事件,如果鼠标光标落在一组坐标(比如一个正方形)之间,就会触发该事件 我知道如果我有一个空表单,我可以简单地连接到mousemove事件,然后离开。但实际上可能有多达10个不同的重叠控件,在我的测试应用程序中,mousemove事件仅在光标位于实际窗体本身上时触发,而不是在其位于子控件上时触发 当设计时有未知数量的子控件时,是否有人知道如何处理此事件 我可以使用简单的一行程序吗?为什么不直接使用控件的鼠标覆盖事件处理程序呢?试试这个: publi

我正在尝试处理一个特定窗体上的mouseclick事件,如果鼠标光标落在一组坐标(比如一个正方形)之间,就会触发该事件

我知道如果我有一个空表单,我可以简单地连接到mousemove事件,然后离开。但实际上可能有多达10个不同的重叠控件,在我的测试应用程序中,mousemove事件仅在光标位于实际窗体本身上时触发,而不是在其位于子控件上时触发

当设计时有未知数量的子控件时,是否有人知道如何处理此事件


我可以使用简单的一行程序吗?

为什么不直接使用控件的鼠标覆盖事件处理程序呢?

试试这个:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        AddMouseMoveHandler(this);
    }

    private void AddMouseMoveHandler(Control c)
    {
        c.MouseMove += MouseMoveHandler;
        if(c.Controls.Count>0)
        {
            foreach (Control ct in c.Controls)
                AddMouseMoveHandler(ct);
        }
    }

    private void MouseMoveHandler(object sender, MouseEventArgs e)
    {
        lblXY.Text = string.Format("X: {0}, Y:{1}", e.X, e.Y);
    }
}

我想这里有一点二进制的情况:没有“一行程序”。我能看到的唯一解决方案是将不实现事件的控件放入一个实现事件的.NET容器中

当任何控件获得单击时,正常的预期行为是它将成为窗体的活动控件(总是可以通过this.ActivceControl访问该控件)

但是,特别是如果您单击的控件捕获了鼠标,那么就必须引发一个事件,因为.NET没有实现事件“冒泡”(就像WPF那样)

处理任何密封对象或其他对象的扩展行为的通常方法是编写一个扩展方法,我发现为控件编写扩展非常容易,但我不知道在这种情况下这是否会对您有所帮助。不幸的是,我现在不在我的祖国,没有VisualStudio可以玩

您可以使用一种策略来确定窗体上的给定点是否在任何控件的边界内,即通过所有窗体控件集合(this.controls)枚举窗体上所有控件的区域(边界)。但是,如果有重叠的控件,则会出现多个控件可能包含给定点的问题


最好的,比尔

我知道我有点晚了,但今天早些时候我用一个面板作为标题栏时遇到了问题。我有一个标签来显示一些文本,一个图片盒和几个按钮,所有这些都嵌套在面板中,但是我需要捕获MouseMove事件

我决定实现一个递归方法处理程序来实现这一点,因为我只有1级嵌套控件,当您开始接近荒谬的嵌套级别时,这可能无法很好地扩展

我是这样做的:

    protected virtual void NestedControl_Mousemove(object sender, MouseEventArgs e)
    {
        Control current = sender as Control;
        //you will need to edit this to identify the true parent of your top-level control. As I was writing a custom UserControl, "this" was my title-bar's parent.
        if (current.Parent != this) 
        {
            // Reconstruct the args to get a correct X/Y value.
            // you can ignore this if you never need to get e.X/e.Y accurately.
            MouseEventArgs newArgs = new MouseEventArgs
            (
                e.Button, 
                e.Clicks, 
                e.X + current.Location.X, 
                e.Y + current.Location.Y, 
                e.Delta
            );
            NestedControl_Mousemove(current.Parent, newArgs);
        }
        else
        {
            // My "true" MouseMove handler, called at last.
            TitlebarMouseMove(current, e);
        }
    }

    //helper method to basically just ensure all the child controls subscribe to the NestedControl_MouseMove event.
    protected virtual void AddNestedMouseHandler(Control root, MouseEventHandler nestedHandler)
    {
        root.MouseMove += new MouseEventHandler(nestedHandler);
        if (root.Controls.Count > 0)
            foreach (Control c in root.Controls)
                AddNestedMouseHandler(c, nestedHandler);
    }
然后设置它相对简单:

定义“真实”处理程序:

然后设置控件事件订阅服务器:

//pnlDisplay is my title bar panel.
AddNestedMouseHandler(pnlDisplay, NestedControl_Mousemove);

使用起来相对简单,而且我可以保证它是有效的:)

我知道这篇文章已经很老了,但在我看来,最简单的方法是让表单实现
IMessageFilter
。在构造函数中(或在
OnHandleCreated
中)调用

然后,您可以在
IMessageFilter.PreFilterMessage
的实现中捕获所有窗口的消息

您可能需要对WIN32 IsChild方法使用p/Invoke

[DllImport("user32.dll")]
public static extern bool IsChild(IntPtr hWndParent, IntPtr hWnd);

与表单的
Handle
属性一起使用,以确保您处理的消息正确。

我使用的控件不公开我需要的事件OP说他使用的控件不实现MouseMove,除非我误解了他。是的,我只有在提交答案后才阅读。这让他可以选择安装全局鼠标挂钩。很高兴你没有删除你的帖子,尽管OP想要其他东西。“在我的处境中帮了我的忙。”村里的“谢谢”帮了我很大的忙。可以更改事件以获得相对位置,如点pt=e位置;控件c=发送方作为控件;如果(sender!=this){//从该子容器循环到(this){//调整每个父容器的点偏移量(c.Left,c.Top);c=c.parent;}而(c!=this);}Show(string.Format(“X:{0},Y:{1}”,pt.X,pt.Y));村民们首先谈到了全球挂钩,你可能希望接受他的答案,而不是我的答案。我还想建议您研究全局鼠标钩子,比如:George Mamaladze的“经典”文章:我可以验证他的全局钩子代码是否能够在VS 2010 beta 2中根据框架编译并运行良好
Application.AddMessageFilter(this);
[DllImport("user32.dll")]
public static extern bool IsChild(IntPtr hWndParent, IntPtr hWnd);