在WPF中获取元素相对于窗口的绝对位置

102

当元素被双击时,我希望能够获取与窗口/根元素相关的元素绝对位置。我只能够获得该元素相对于其父元素的位置,而我想要获得相对于窗口的位置。我已经看到了如何在屏幕上获取元素点的解决方案,但没有看到如何在窗口上获取。

6个回答

143

我认为BrandonS想要的不是鼠标相对于根元素的位置,而是某个后代元素的位置。

为此,有一个名为TransformToAncestor的方法:

Point relativePoint = myVisual.TransformToAncestor(rootVisual)
                              .Transform(new Point(0, 0));

当双击元素时,myVisual代表该元素本身,而rootVisual则代表与应用程序主窗口或其他你所需的元素的位置相关联。


3
你好,我尝试了这个操作,但出现了以下异常:System.InvalidOperationException was unhandled Message=The specified Visual is not an ancestor of this Visual. Source=PresentationCore 你有什么想法吗? - RoflcoptrException
8
如果您想获取两个元素之间的相对位置关系,但它们不互相包含,则可以使用Visual.TransformToVisual方法。而如果要使用Visual.TransformToAncestor方法,必须传入一个包含这两个元素的Visual作为参数。请注意,翻译后保持原意,让内容易于理解,无需添加解释或其他额外的信息。 - Robert Macnee
6
TransformToVisual仍然需要一个共同的祖先,如果控件在弹出窗口中,这可能会有问题。 - Adam Mills
1
超级直观!他们不能把这个包装在一个“GetRelativePosition”调用中吗? :-) 感谢您的帮助。+1 - Paul
@Paul - 试着写一个扩展方法吧! - cod3monk3y
2
@cod3monk3y - 或许,如果微软开源WPF的话,我会给他们发送一个pull请求 :-) - Paul

51

要获取窗口内 UI 元素的绝对位置,您可以使用:

Point position = desiredElement.PointToScreen(new Point(0d, 0d));
如果您在用户控件内部,并且只想要该控件内部UI元素的相对位置,请使用:

Point position = desiredElement.PointToScreen(new Point(0d, 0d)),
controlPosition = this.PointToScreen(new Point(0d, 0d));

position.X -= controlPosition.X;
position.Y -= controlPosition.Y;

5
请注意,如果您的显示器缩放没有设置为100%(即在高DPI屏幕上),则可能不会按照您的预期执行此操作。 - Drew Noakes

20

将此方法添加到静态类中:

 public static Rect GetAbsolutePlacement(this FrameworkElement element, bool relativeToScreen = false)
    {
        var absolutePos = element.PointToScreen(new System.Windows.Point(0, 0));
        if (relativeToScreen)
        {
            return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight);
        }
        var posMW = Application.Current.MainWindow.PointToScreen(new System.Windows.Point(0, 0));
        absolutePos = new System.Windows.Point(absolutePos.X - posMW.X, absolutePos.Y - posMW.Y);
        return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight);
    }

relativeToScreen参数设置为true可使元素相对于整个屏幕的左上角定位,或将其设置为false可使元素相对于应用程序窗口的左上角定位。


1
这个功能非常棒!我正在将其与一个动画一起使用,通过修改元素的RenderTransform来滑动图像进入或离开屏幕,因此它需要知道元素在屏幕上的绝对位置。 - cod3monk3y

9
自 .NET 3.0 开始,您可以简单地使用*yourElement*.TranslatePoint(new Point(0, 0), *theContainerOfYourChoice*)
这将为您提供按钮相对于容器的点0,0。(您也可以给出其他点而不是0,0)
请参阅此处的文档: 链接

0
childObj.MouseDown += (object sender, MouseButtonEventArgs e) =>
{
    Vector parent = (Vector)e.GetPosition(parentObj);
    Vector child = (Vector)e.GetPosition(childObj); // sender
    Point childPosition = (Point)(parent - child);
};

-2

嗯。 你必须指定你点击的窗口 Mouse.GetPosition(IInputElement relativeTo) 以下代码对我很有效

protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);
        Point p = e.GetPosition(this);
    }

我猜你需要从应用程序的其他地方而不是它自己的类中引用窗口。在这种情况下,Application.Current.MainWindow会帮助你。

尽管这不是作者要求的,但它让我走上了正确的轨道,谢谢。 - Ladislav Ondris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接