Obtener la posición absoluta del elemento dentro de la ventana en wpf

88

Me gustaría obtener la posición absoluta de un elemento en relación con la ventana / elemento raíz cuando se hace doble clic en él. La posición relativa del elemento dentro de su padre es todo a lo que puedo llegar, y lo que estoy tratando de alcanzar es el punto relativo a la ventana. He visto soluciones sobre cómo obtener el punto de un elemento en la pantalla, pero no en la ventana.

BrandonS
fuente

Respuestas:

127

Creo que lo que BrandonS quiere no es la posición del mouse en relación con el elemento raíz, sino la posición de algún elemento descendiente.

Para eso, existe el método TransformToAncestor :

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

¿Dónde myVisualestá el elemento en el que se acaba de hacer doble clic, y rootVisuales Application.Current.MainWindow o lo que sea que desee la posición relativa.

Robert Macnee
fuente
2
Hola, probé esto y obtengo la siguiente excepción: System.InvalidOperationException no se manejó Mensaje = El Visual especificado no es un antepasado de este Visual. Fuente = PresentationCore ¿Alguna idea?
RoflcoptrException
8
Visual.TransformToAncestor solo funcionará si pasa un Visual. Si desea la posición relativa de dos elementos y uno no contiene al otro, puede usar Visual.TransformToVisual en su lugar.
Robert Macnee
5
TransformToVisual aún requiere un ancestro común que puede ser problemático si el control está en una ventana emergente
Adam Mills
1
¡Súper intuitivo! ¿No pueden envolver esto en una llamada "GetRelativePosition"? :-) Gracias por la ayuda. +1
Paul
1
@ cod3monk3y - o quizás, tal vez si Microsoft abre las fuentes WPF, les enviaré una solicitud de extracción :-)
Paul
41

Para obtener la posición absoluta de un elemento de la interfaz de usuario dentro de la ventana, puede usar:

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

Si está dentro de un control de usuario y simplemente desea la posición relativa del elemento de la interfaz de usuario dentro de ese control, simplemente 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
fuente
4
Tenga en cuenta que esto probablemente no haga lo que espera si la escala de su pantalla no está configurada al 100% (es decir, en pantallas de DPI alto).
Drew Noakes
18

Agregue este método a una clase estática:

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

Configure el relativeToScreenparámetro en truepara colocarlo desde la esquina superior izquierda de toda la pantalla o en falsepara colocarlo en la esquina superior izquierda de la ventana de la aplicación.

Andreas
fuente
1
¡Esto funciona fantásticamente! Estoy usando esto con una animación que desliza una imagen dentro o fuera de la pantalla modificando la RenderTransformdel elemento y, por lo tanto, necesita saber la posición absoluta del elemento en la pantalla.
cod3monk3y
6

Desde .NET 3.0, simplemente puede usar *yourElement*.TranslatePoint(new Point(0, 0), *theContainerOfYourChoice*).

Esto le dará el punto 0, 0 de su botón, pero hacia el contenedor. (También puede dar otro punto que 0, 0)

Consulte aquí el documento.

Guibi
fuente
0

Hm. Tienes que especificar la ventana en la que hiciste clic en El Mouse.GetPosition(IInputElement relativeTo) siguiente código funciona bien para mí

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

Sospecho que necesita hacer referencia a la ventana no desde su propia clase sino desde otro punto de la aplicación. En este caso Application.Current.MainWindowte ayudará.

Oleg
fuente
Aunque no es lo que pidió el autor, me puso en el camino correcto, gracias
Ladislav Ondris