2011-01-26 14 views
11

Necesito saber la posición de una ventana que está maximizada.¿Cómo puedo encontrar la posición de una ventana maximizada?

La ventana WPF tiene propiedades superiores e izquierdas que especifican la ubicación de la ventana. Sin embargo, si maximiza la ventana, estas propiedades mantienen los valores de la ventana en su estado normal.

Si se ejecuta en una configuración de pantalla única, la posición maximizada es naturalmente (0,0). Sin embargo, si tiene varias pantallas, eso no es necesariamente cierto. La ventana solo tendrá posición (0,0) si la tiene maximizada en la pantalla principal.

Entonces ... ¿hay alguna manera de averiguar la posición de una ventana maximizada (preferiblemente en las mismas unidades lógicas que las propiedades Superior e Izquierda)?

Respuesta

0

Me doy cuenta de que está trabajando en WPF, y esta respuesta hace uso de la tecnología Forms, pero debería funcionar sin mucha dificultad.

Puede obtener una colección de las pantallas a través de My.Settings.Screens.AllScreens. Desde allí puede acceder a la resolución en la que la pantalla está trabajando actualmente.

Dado que las ventanas WPF retienen los valores Top/Left que tenían cuando se maximizaban, puede determinar en qué pantalla se encuentran al determinar a qué pantalla se refieren las coordenadas Top/Left y luego obtener la parte superior/izquierda coordinar para esa pantalla.

Lamentablemente, estoy en el camino, y no puedo probar esto en este momento. Si lo implementa, me gustaría ver lo que se te ocurra.

7

Finalmente encontré una solución de trabajo para mí: (gracias)

private System.Drawing.Rectangle getWindowRectangle() 
{ 
    System.Drawing.Rectangle windowRectangle; 

    if (this.WindowState == System.Windows.WindowState.Maximized) 
    { 
     /* Here is the magic: 
     * Use Winforms code to find the Available space on the 
     * screen that contained the window 
     * just before it was maximized 
     * (Left, Top have their values from Normal WindowState) 
     */ 
     windowRectangle = System.Windows.Forms.Screen.GetWorkingArea(
      new System.Drawing.Point((int)this.Left, (int)this.Top)); 
    } 
    else 
    { 
     windowRectangle = new System.Drawing.Rectangle(
      (int)this.Left, (int)this.Top, 
      (int)this.ActualWidth, (int)this.ActualHeight); 
    } 

    return windowRectangle; 
} 
+2

Creo que si cambia la llamada GetWorkingArea a: windowRectangle = System.Windows.Forms.Screen.GetWorkingArea (new System.Drawing.Point ((int) window.Left + (int) (window.ActualWidth/2), (int) window.Top + (int) (window.ActualHeight/2))); eso lo arreglará Necesita obtener el centro de la ventana, no el topleft, porque ese es el punto que WPF usa para determinar a qué ventana se debe maximizar, si la ventana se encuentra en más de un monitor. – Matt

+1

buena idea, pero ¿esto realmente ayuda? esta rama de la cláusula if solo se usa cuando se maximiza WindowState, entonces ActualWith y -Height serán sobre el tamaño de la pantalla, no sobre el windowsize (restaurado) – eFloh

+0

Sí, entiendo lo que dices. ¿se puede obtener el tamaño de la ventana restaurada de RestoreBounds y luego usar eso en vez de ActualWidth/ActualHeight tal vez? – Matt

6

Aquí está la solución que se me ocurrió sobre la base de la discusión anterior aquí.

Esta solución ...

  • devuelve la posición de una ventana en su estado actual
  • maneja todos los estados de ventana (maximizada, minimizada, restaurado)
  • no depende de las formas de Windows (pero está inspirado por ella)
  • utiliza el identificador de ventana para determinar de manera fiable el monitor correcto

el met principal od GetAbsolutePosition se implementa aquí como un método de extensión. Si usted tiene un Window llamada myWindow, lo llaman así:

Point p = myWindow.GetAbsolutePosition(); 

Aquí está el código completo:

using System; 
using System.Windows; 
using System.Windows.Interop; 
using System.Runtime.InteropServices; 

static class OSInterop 
{ 
    [DllImport("user32.dll")] 
    public static extern int GetSystemMetrics(int smIndex); 
    public const int SM_CMONITORS = 80; 

    [DllImport("user32.dll")] 
    public static extern bool SystemParametersInfo(int nAction, int nParam, ref RECT rc, int nUpdate); 

    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    public static extern bool GetMonitorInfo(HandleRef hmonitor, [In, Out] MONITORINFOEX info); 

    [DllImport("user32.dll")] 
    public static extern IntPtr MonitorFromWindow(HandleRef handle, int flags); 

    public struct RECT 
    { 
     public int left; 
     public int top; 
     public int right; 
     public int bottom; 
     public int width { get { return right - left; } } 
     public int height { get { return bottom - top; } } 
    } 

    [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)] 
    public class MONITORINFOEX 
    { 
     public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX)); 
     public RECT rcMonitor = new RECT(); 
     public RECT rcWork = new RECT(); 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 
     public char[] szDevice = new char[32]; 
     public int dwFlags; 
    } 
} 

static class WPFExtensionMethods 
{ 
    public static Point GetAbsolutePosition(this Window w) 
    { 
     if (w.WindowState != WindowState.Maximized) 
      return new Point(w.Left, w.Top); 

     Int32Rect r; 
     bool multimonSupported = OSInterop.GetSystemMetrics(OSInterop.SM_CMONITORS) != 0; 
     if (!multimonSupported) 
     { 
      OSInterop.RECT rc = new OSInterop.RECT(); 
      OSInterop.SystemParametersInfo(48, 0, ref rc, 0); 
      r = new Int32Rect(rc.left, rc.top, rc.width, rc.height); 
     } 
     else 
     { 
      WindowInteropHelper helper = new WindowInteropHelper(w); 
      IntPtr hmonitor = OSInterop.MonitorFromWindow(new HandleRef((object)null, helper.EnsureHandle()), 2); 
      OSInterop.MONITORINFOEX info = new OSInterop.MONITORINFOEX(); 
      OSInterop.GetMonitorInfo(new HandleRef((object)null, hmonitor), info); 
      r = new Int32Rect(info.rcWork.left, info.rcWork.top, info.rcWork.width, info.rcWork.height); 
     } 
     return new Point(r.X, r.Y); 
    } 
} 
+1

Esta debería ser la solución aceptada. ¡Gracias! –

3
public static System.Drawing.Rectangle GetWindowRectangle(this Window w) 
{ 
    if (w.WindowState == WindowState.Maximized) { 
     var handle = new System.Windows.Interop.WindowInteropHelper(w).Handle; 
     var screen = System.Windows.Forms.Screen.FromHandle(handle); 
     return screen.WorkingArea; 
    } 
    else { 
     return new System.Drawing.Rectangle(
      (int)w.Left, (int)w.Top, 
      (int)w.ActualWidth, (int)w.ActualHeight); 
    } 
} 
+0

Ricitos de Oro! La primera solución fue compacta pero errónea, la segunda fue probablemente la correcta, pero no compacta. Este es el correcto :) Por alguna razón, los 3 se votan en orden inverso a su valor real. –

+0

No da la respuesta correcta para mí – Epirocks

3

universal respuesta de una línea de trabajo para todos los monitores y todos de alta DPI variantes:

Point leftTop = this.PointToScreen(new Point(0, 0)); 

Esto, por ejemplo, devuelve (-8, -8) para una ventana que está maximizada o n una pantalla ancha de 1920 cuyo ActualWidth devuelve 1936.

Sólo una queja a las otras respuestas: No confunda nunca lógicas 96 dpi píxeles WPF (utilizando double) con píxeles reales nativas (usando int) - en especial con sólo fundición doble a int!

+0

Obviamente no funciona en configuraciones de múltiples monitores. – Kilazur

+0

@Kilazur ¿por qué obviamente? Inicialmente probé esto en una cabeza triple en los 3 monitores. La barra de tareas es vertical y no está en la pantalla principal, lo que enloquece por completo el 50% de todo el software. – springy76

+1

El punto (0,0) está dentro del área del cliente de la ventana y no devuelve la esquina real superior/izquierda del marco de la ventana. Si intenta usar estas coordenadas para colocar algo más, sale mal. –

Cuestiones relacionadas