101

I would like to get the absolute position of an element in relation to the window/root element when it is double clicked. The element's relative position within it's parent is all I can seem to get to, and what I'm trying to get to is the point relative to the window. I've seen solutions of how to get a the point of an element on the screen, but not in the window.

animuson
  • 53,861
  • 28
  • 137
  • 147
BrandonS
  • 2,513
  • 7
  • 28
  • 29

6 Answers6

142

I think what BrandonS wants is not the position of the mouse relative to the root element, but rather the position of some descendant element.

For that, there is the TransformToAncestor method:

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
  • 11,650
  • 4
  • 40
  • 35
  • 3
    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 Oct 28 '10 at 09:21
  • 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 Nov 01 '10 at 16:26
  • 5
    TransformToVisual still requires a common ancestor which can be problematic if the control is in a popup – Adam Mills Nov 21 '11 at 14:47
  • 1
    Super intuitive! Can't they wrap this in a "GetRelativePosition" call? :-) Thanks for the help. +1 – Paul Oct 08 '12 at 22:41
  • @Paul - Try writing an [extension method](https://msdn.microsoft.com/en-us/library/bb383977.aspx)! – cod3monk3y Feb 03 '15 at 21:02
  • 2
    @cod3monk3y - or perhaps, maybe if Microsoft open sources WPF, I'll send them a pull request :-) – Paul Feb 04 '15 at 14:49
51

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 a 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;
starball
  • 20,030
  • 7
  • 43
  • 238
Filip
  • 854
  • 8
  • 17
  • 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 Apr 07 '16 at 14:27
20

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.

E Mett
  • 2,272
  • 3
  • 18
  • 37
Andreas
  • 3,843
  • 3
  • 40
  • 53
  • 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 Feb 05 '15 at 00:24
9

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.

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Guibi
  • 115
  • 1
  • 7
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);
};
Dejwid
  • 1
-2

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
  • 1,100
  • 2
  • 11
  • 16