GetChildAtPoint方法返回错误的控件

时间:2011-09-22 02:35:50

标签: c# winforms cursor-position

我的表单层次结构是这样的:

Form -> TableLayoutOne -> TableLayoutTwo -> Panel -> ListBox

在ListBox的MouseMove事件中,我有这样的代码:

    Point cursosPosition2 = PointToClient(new Point(Cursor.Position.X, Cursor.Position.Y));
    Control crp = this.GetChildAtPoint(cursosPosition2);
    if (crp != null)
        MessageBox.Show(crp.Name);

MessageBox向我显示“TableLayoutOne”,但我希望它向我显示“ListBox”。我的代码在哪里,我错了?感谢。

2 个答案:

答案 0 :(得分:7)

GetChildFromPoint()方法使用原生ChildWindowFromPointEx()方法,其文档说明:

  

确定属于哪个子窗口的子窗口(如果有)   指定的父窗口包含指定的点。功能可以   忽略不可见,禁用和透明的子窗口。 搜索   仅限于直接的儿童窗户。孙子孙女更深   未搜索后代。

请注意粗体文字:该方法无法获得您想要的效果。

理论上,您可以在返回的控件上调用GetChildFromPoint(),直到获得null

Control crp = this.GetChildAtPoint(cursosPosition2);
Control lastCrp = crp;

while (crp != null)
{
    lastCrp = crp;
    crp = crp.GetChildAtPoint(cursorPosition2);
}

然后你知道lastCrp是那个位置的最低后代。

答案 1 :(得分:1)

更好的代码可以编写如下:

Public Control FindControlAtScreenPosition(Form form, Point p)
{
    if (!form.Bounds.Contains(p)) return null; //not inside the form
    Control c = form, c1 = null;
    while (c != null)
    {
        c1 = c;
        c = c.GetChildAtPoint(c.PointToClient(p), GetChildAtPointSkip.Invisible | GetChildAtPointSkip.Transparent); //,GetChildAtPointSkip.Invisible
    }
    return c1;
}

用法如下:

Control c = FindControlAtScreenPosition(this, Cursor.Position);