2010-08-30 10 views
5

Jaki jest poprawny sposób na odzyskanie pozycji okna w WPF?Okno ActualTop, ActualLeft

Oto kilka prób, które zrobiłem. Pierwsza próba, oczywiste, to oczywiste, ale to zwraca "złe" położenie, gdy okno jest zmaksymalizowane. Druga próba:

Point GetPosition(Window win) 
{ 
    if (win.WindowState == WindowState.Maximized) 
     return new Point(0, 0); 
    else 
     return new Point(win.Top, win.Left); 
} 

Prawie tam, ale wciąż jest problem: gdy masz dwie (lub więcej), ekrany, a okno jest zmaksymalizowane w drugim ekranie pojawi się (0, 0) stanowisko, że nie odzwierciedlają rzeczywistą pozycję okna.

Zauważyłem, że Window ma _actualTop i _actualLeft członków prywatnych, ale nie ma właściwości publicznej, aby je narazić.

W jaki sposób odzyskujesz poprawną wartość?

Odpowiedz

3

Tak, niezręczny. Masz większe problemy, (0, 0) nie będzie ważne nawet na głównym monitorze, jeśli użytkownik umieści pasek zadań po lewej lub na górze. Jak ja zrobiłem. Możesz uzyskać pomoc z klasy Windows Forms Screen. Użyj jego metody FromPoint(), a następnie właściwości WorkingArea. Lub właściwość Bounds, jeśli zezwolisz, aby okno przechodziło w tryb pełnoekranowy.

Osobiście po prostu P/Invoke GetWindowRect().

+0

Dzięki Hans, P/Invoking GetWindowRect() faktycznie rozwiązuje problem. Nie za miły, ale działa zgodnie z oczekiwaniami. Dzięki jeszcze raz! –

+0

Co jest nie tak z 'Point leftTop = this.PointToScreen (new Point (0, 0));'? – springy76

+0

Poza tym, że nie jest to kod WPF, po prostu spróbuj i umieść pasek zadań po lewej stronie. –

13

Można użyć refleksji, jeśli nie chcesz polegać na WinForm lub PI

private double GetWindowLeft(Window window) 
    { 
     if (window.WindowState == WindowState.Maximized) 
     { 
      var leftField = typeof(Window).GetField("_actualLeft", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); 
      return (double)leftField.GetValue(window); 
     } 
     else 
      return window.Left; 
    } 
+0

to działa idealnie. Możesz również uzyskać pozycję "Góra" w ten sam sposób (_actualTop) –

3

Oto rozwiązanie, które opiera się na P/Invoke z GetWindowRect, ale używa metody rozszerzenie, aby Twój kod wyglądać ładniej. Używasz myWindow.ActualTop() i myWindow.ActualLeft() w swoim kodzie.

static class WindowExtensions 
{ 
    [StructLayout(LayoutKind.Sequential)] 
    struct RECT 
    { 
     public int Left; 
     public int Top; 
     public int Right; 
     public int Bottom; 
    } 
    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); 


    public static double ActualTop(this Window window) 
    { 
     switch (window.WindowState) 
     { 
      case WindowState.Normal: 
       return window.Top; 
      case WindowState.Minimized: 
       return window.RestoreBounds.Top; 
      case WindowState.Maximized: 
       { 
        RECT rect; 
        GetWindowRect((new WindowInteropHelper(window)).Handle, out rect); 
        return rect.Top; 
       } 
     } 
     return 0; 
    } 
    public static double ActualLeft(this Window window) 
    { 
     switch (window.WindowState) 
     { 
      case WindowState.Normal: 
       return window.Left; 
      case WindowState.Minimized: 
       return window.RestoreBounds.Left; 
      case WindowState.Maximized: 
       { 
        RECT rect; 
        GetWindowRect((new WindowInteropHelper(window)).Handle, out rect); 
        return rect.Left; 
       } 
     } 
     return 0; 
    } 
}