Uzyskaj bezwzględną pozycję elementu w oknie w wpf

88

Chciałbym uzyskać bezwzględną pozycję elementu w stosunku do elementu window / root po dwukrotnym kliknięciu. Względne położenie elementu w jego rodzicu to wszystko, do czego mogę się dostać, a to, do czego próbuję dotrzeć, to punkt względem okna. Widziałem rozwiązania, jak uzyskać punkt elementu na ekranie, ale nie w oknie.

BrandonS
źródło

Odpowiedzi:

127

Myślę, że BrandonS nie chce pozycji myszy względem elementu głównego, ale raczej pozycji jakiegoś elementu podrzędnego.

W tym celu istnieje metoda TransformToAncestor :

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

Where myVisual is the element that was just double-clicked, and rootVisual is Application.Current.MainWindow or whatever you want the position relative to.

Robert Macnee
źródło
2
Hi i tried this and i get the following exception: System.InvalidOperationException was unhandled Message=The specified Visual is not an ancestor of this Visual. Source=PresentationCore Any idea?
RoflcoptrException
8
Visual.TransformToAncestor will only work if you pass in a containing Visual. If you want the relative position of two elements and one doesn't contain the other, you can use Visual.TransformToVisual instead.
Robert Macnee
5
TransformToVisual still requires a common ancestor which can be problematic if the control is in a popup
Adam Mills
1
Super intuitive! Can't they wrap this in a "GetRelativePosition" call? :-) Thanks for the help. +1
Paul
1
@cod3monk3y - or perhaps, maybe if Microsoft open sources WPF, I'll send them a pull request :-)
Paul
42

To get the absolute position of an UI element within the window you can use:

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

If you are within an User Control, and simply want relative position of the UI element within that control, simply use:

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

position.X -= controlPosition.X;
position.Y -= controlPosition.Y;
Filip
źródło
4
Note that this probably doesn't do what you expect if your display scaling isn't set to 100% (ie on high DPI screens).
Drew Noakes
18

Add this method to a static class:

 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);
    }

Set relativeToScreen paramater to true for placement from top left corner of whole screen or to false for placement from top left corner of application window.

Andreas
źródło
1
This works fantastically! I'm using this with an animation that slides an image on- or off-screen by modifying the RenderTransform of the element, and therefore it needs to know the absolute position of the element on the screen.
cod3monk3y
6

Since .NET 3.0, you can simply use *yourElement*.TranslatePoint(new Point(0, 0), *theContainerOfYourChoice*).

This will give you the point 0, 0 of your button, but towards the container. (You can also give an other point that 0, 0)

Check here for the doc.

Guibi
źródło
0

Hm. You have to specify window you clicked in Mouse.GetPosition(IInputElement relativeTo) Following code works well for me

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

I suspect that you need to refer to the window not from it own class but from other point of the application. In this case Application.Current.MainWindow will help you.

Oleg
źródło
Even though it's not what the author asked for, it got me on the right track, thanks
Ladislav Ondris