Dapatkan Posisi Absolut elemen dalam jendela di wpf

89

Saya ingin mendapatkan posisi absolut dari sebuah elemen dalam kaitannya dengan elemen jendela / root ketika diklik dua kali. Posisi relatif elemen dalam induknya adalah semua yang bisa saya capai, dan yang saya coba tuju adalah titik relatif ke jendela. Saya telah melihat solusi tentang cara mendapatkan titik elemen di layar, tetapi tidak di jendela.

BrandonS
sumber

Jawaban:

130

Menurut saya yang diinginkan BrandonS bukanlah posisi mouse relatif terhadap elemen root, melainkan posisi beberapa elemen turunan.

Untuk itu, ada metode TransformToAncestor :

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

Di mana myVisualelemen yang baru saja diklik dua kali, dan rootVisualApplication.Current.MainWindow atau apa pun yang Anda inginkan posisinya relatif.

Robert Macnee
sumber
3
Hai, saya mencoba ini dan saya mendapatkan pengecualian berikut: System.InvalidOperationException tidak ditangani Message = Visual yang ditentukan bukanlah leluhur dari Visual ini. Sumber = PresentationCore Ada ide?
RoflcoptrException
8
Visual.TransformToAncestor hanya akan berfungsi jika Anda mengirimkan Visual. Jika Anda ingin posisi relatif dari dua elemen dan yang satu tidak berisi yang lain, Anda dapat menggunakan Visual.TransformToVisual.
Robert Macnee
5
TransformToVisual masih membutuhkan nenek moyang yang sama yang dapat menjadi masalah jika kontrol dalam popup
Adam Mills
1
Sangat intuitif! Tidak bisakah mereka menggabungkan ini dalam panggilan "GetRelativePosition"? :-) Terima kasih untuk bantuannya. +1
Paul
1
@ cod3monk3y - atau mungkin, mungkin jika Microsoft open source WPF, saya akan mengirimi mereka permintaan tarik :-)
Paul
43

Untuk mendapatkan posisi absolut dari elemen UI di dalam jendela, Anda dapat menggunakan:

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

Jika Anda berada dalam Kontrol Pengguna, dan hanya ingin posisi relatif dari elemen UI dalam kontrol itu, cukup gunakan:

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

position.X -= controlPosition.X;
position.Y -= controlPosition.Y;
Filip
sumber
4
Perhatikan bahwa ini mungkin tidak melakukan apa yang Anda harapkan jika penskalaan tampilan Anda tidak disetel ke 100% (yaitu pada layar DPI tinggi).
Drew Noakes
18

Tambahkan metode ini ke kelas statis:

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

Atur relativeToScreenparameter ke trueuntuk penempatan dari sudut kiri atas seluruh layar atau falseuntuk penempatan dari sudut kiri atas jendela aplikasi.

Andreas
sumber
1
Ini bekerja dengan luar biasa! Saya menggunakan ini dengan animasi yang menggeser gambar ke dalam atau di luar layar dengan memodifikasi RenderTransformelemen, dan karena itu perlu mengetahui posisi absolut elemen di layar.
cod3monk3y
6

Sejak .NET 3.0, Anda cukup menggunakan *yourElement*.TranslatePoint(new Point(0, 0), *theContainerOfYourChoice*).

Ini akan memberi Anda poin 0, 0 dari tombol Anda, tetapi ke arah wadah. (Anda juga dapat memberikan poin lain bahwa 0, 0)

Cek di sini untuk dok.

Guibi
sumber
0

Hm. Anda harus menentukan jendela yang Anda klik di Mouse.GetPosition(IInputElement relativeTo) Kode berikut berfungsi dengan baik untuk saya

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

Saya menduga bahwa Anda perlu merujuk ke jendela bukan dari kelasnya sendiri tetapi dari titik aplikasi lain. Dalam hal ini Application.Current.MainWindowakan membantu Anda.

Oleg
sumber
Meskipun bukan itu yang diminta penulis, itu membuat saya berada di jalur yang benar, terima kasih
Ladislav Ondris