Holen Sie sich die absolute Position des Elements innerhalb des Fensters in wpf

86

Ich möchte die absolute Position eines Elements in Bezug auf das Fenster / Stammelement erhalten, wenn es doppelt angeklickt wird. Die relative Position des Elements innerhalb des übergeordneten Elements ist alles, was ich zu erreichen scheint, und ich versuche, den Punkt relativ zum Fenster zu erreichen. Ich habe Lösungen gesehen, wie man den Punkt eines Elements auf dem Bildschirm erhält, aber nicht im Fenster.

BrandonS
quelle

Antworten:

125

Ich denke, BrandonS möchte nicht die Position der Maus relativ zum Wurzelelement, sondern die Position eines Nachkommenelements.

Dafür gibt es die TransformToAncestor- Methode:

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

Wo myVisualist das Element, auf das nur doppelklickt wurde, und rootVisualist Application.Current.MainWindow oder was auch immer Sie die Position relativ zu wollen.

Robert Macnee
quelle
2
Hallo, ich habe dies versucht und erhalte die folgende Ausnahme: System.InvalidOperationException wurde nicht behandelt Nachricht = Das angegebene Visual ist kein Vorfahr dieses Visual. Source = PresentationCore Irgendeine Idee?
RoflcoptrException
8
Visual.TransformToAncestor funktioniert nur, wenn Sie ein enthaltenes Visual übergeben. Wenn Sie die relative Position von zwei Elementen wünschen und eines das andere nicht enthält, können Sie stattdessen Visual.TransformToVisual verwenden.
Robert Macnee
5
TransformToVisual erfordert immer noch einen gemeinsamen Vorfahren, was problematisch sein kann, wenn sich das Steuerelement in einem Popup befindet
Adam Mills
1
Super intuitiv! Können sie dies nicht in einen "GetRelativePosition" -Aufruf einschließen? :-) Danke für die Hilfe. +1
Paul
1
@ cod3monk3y - oder vielleicht, wenn Microsoft Open Source WPF, werde ich ihnen eine Pull-Anfrage senden :-)
Paul
41

Um die absolute Position eines UI-Elements innerhalb des Fensters zu ermitteln, können Sie Folgendes verwenden:

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

Wenn Sie sich innerhalb eines Benutzersteuerelements befinden und einfach die relative Position des UI-Elements innerhalb dieses Steuerelements wünschen, verwenden Sie einfach:

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

position.X -= controlPosition.X;
position.Y -= controlPosition.Y;
Filip
quelle
3
Beachten Sie, dass dies wahrscheinlich nicht das tut, was Sie erwarten, wenn Ihre Anzeigeskalierung nicht auf 100% eingestellt ist (dh auf Bildschirmen mit hoher DPI).
Drew Noakes
18

Fügen Sie diese Methode einer statischen Klasse hinzu:

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

relativeToScreenStellen Sie den Parameter auf truefür die Platzierung in der oberen linken Ecke des gesamten Bildschirms oder falsefür die Platzierung in der oberen linken Ecke des Anwendungsfensters.

Andreas
quelle
1
Das funktioniert fantastisch! Ich verwende dies mit einer Animation, bei der ein Bild durch Ändern RenderTransformdes Elements auf dem Bildschirm oder außerhalb des Bildschirms verschoben wird. Daher muss die absolute Position des Elements auf dem Bildschirm bekannt sein.
cod3monk3y
5

Seit .NET 3.0 können Sie einfach verwenden *yourElement*.TranslatePoint(new Point(0, 0), *theContainerOfYourChoice*).

Dies gibt Ihnen den Punkt 0, 0 Ihrer Schaltfläche, jedoch in Richtung des Containers. (Sie können auch einen anderen Punkt als 0, 0 angeben.)

Überprüfen Sie hier für das Dokument.

Guibi
quelle
0

Hm. Sie müssen das Fenster angeben, auf das Sie im Mouse.GetPosition(IInputElement relativeTo) folgenden Code geklickt haben. Das funktioniert gut für mich

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

Ich vermute, dass Sie auf das Fenster nicht von seiner eigenen Klasse, sondern von einem anderen Punkt der Anwendung aus verweisen müssen. In diesem Fall Application.Current.MainWindowwird Ihnen helfen.

Oleg
quelle
Obwohl es nicht das ist, wonach der Autor gefragt hat, hat es mich auf den richtigen Weg gebracht, danke
Ladislav Ondris