Obtenir la position absolue de l'élément dans la fenêtre dans wpf

88

Je voudrais obtenir la position absolue d'un élément par rapport à l'élément window / root quand il est double-cliqué. La position relative de l'élément dans son parent est tout ce que je peux sembler atteindre, et ce que j'essaie d'arriver est le point relatif à la fenêtre. J'ai vu des solutions pour obtenir le point d'un élément sur l'écran, mais pas dans la fenêtre.

BrandonS
la source

Réponses:

127

Je pense que ce que veut BrandonS n'est pas la position de la souris par rapport à l'élément racine, mais plutôt la position d'un élément descendant.

Pour cela, il existe la méthode TransformToAncestor :

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

myVisualest l'élément sur lequel vous venez de double-cliquer, et rootVisualest Application.Current.MainWindow ou tout ce à quoi vous voulez la position relative.

Robert Macnee
la source
2
Salut, j'ai essayé cela et j'obtiens l'exception suivante: System.InvalidOperationException n'a pas été gérée Message = Le visuel spécifié n'est pas un ancêtre de ce visuel. Source = PresentationCore Une idée?
RoflcoptrException
8
Visual.TransformToAncestor ne fonctionnera que si vous transmettez un Visual contenant. Si vous voulez la position relative de deux éléments et que l'un ne contient pas l'autre, vous pouvez utiliser Visual.TransformToVisual à la place.
Robert Macnee
5
TransformToVisual nécessite toujours un ancêtre commun qui peut être problématique si le contrôle est dans un popup
Adam Mills
1
Super intuitif! Ne peuvent-ils pas envelopper cela dans un appel "GetRelativePosition"? :-) Merci pour l'aide. +1
Paul
1
@ cod3monk3y - ou peut-être, si Microsoft ouvre les sources WPF, je leur enverrai une pull request :-)
Paul
41

Pour obtenir la position absolue d'un élément de l'interface utilisateur dans la fenêtre, vous pouvez utiliser:

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

Si vous êtes dans un contrôle utilisateur et souhaitez simplement la position relative de l'élément d'interface utilisateur dans ce contrôle, utilisez simplement:

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

position.X -= controlPosition.X;
position.Y -= controlPosition.Y;
Filip
la source
4
Notez que cela ne fait probablement pas ce que vous attendez si la mise à l'échelle de votre affichage n'est pas réglée sur 100% (c'est-à-dire sur les écrans à haute résolution).
Drew Noakes le
18

Ajoutez cette méthode à une classe statique:

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

Définissez le relativeToScreenparamètre sur truepour le placement à partir du coin supérieur gauche de tout l'écran ou sur falsepour le placement à partir du coin supérieur gauche de la fenêtre d'application.

Andreas
la source
1
Cela fonctionne à merveille! J'utilise cela avec une animation qui fait glisser une image sur ou hors écran en modifiant le RenderTransformde l'élément, et par conséquent, il a besoin de connaître la position absolue de l'élément sur l'écran.
cod3monk3y
6

Depuis .NET 3.0, vous pouvez simplement utiliser *yourElement*.TranslatePoint(new Point(0, 0), *theContainerOfYourChoice*).

Cela vous donnera le point 0, 0 de votre bouton, mais vers le conteneur. (Vous pouvez également donner un autre point que 0, 0)

Vérifiez ici pour le doc.

Guibi
la source
0

Hm. Vous devez spécifier la fenêtre sur laquelle vous avez cliqué dans le Mouse.GetPosition(IInputElement relativeTo) code suivant fonctionne bien pour moi

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

Je soupçonne que vous devez vous référer à la fenêtre non pas depuis sa propre classe mais depuis un autre point de l'application. Dans ce cas Application.Current.MainWindow, vous aidera.

Oleg
la source
Même si ce n'est pas ce que l'auteur a demandé, cela m'a mis sur la bonne voie, merci
Ladislav Ondris