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.

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.


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;

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.


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.


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.


Même si ce n'est pas ce que l'auteur a demandé, cela m'a mis sur la bonne voie, merci
Ladislav Ondris
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.