2011-01-26 10 views
11

Ho bisogno di conoscere la posizione di una finestra che è massimizzata.Come posso trovare la posizione di una finestra ingrandita?

La finestra WPF ha le proprietà superiore e sinistra che specifica la posizione della finestra. Tuttavia, se si ingrandisce la finestra queste proprietà mantengono i valori della finestra nel suo stato normale.

Se si esegue una configurazione a schermo singolo, la posizione ingrandita è naturale (0,0). Tuttavia, se hai più schermi che non è necessariamente vero. La finestra avrà solo la posizione (0,0) se la si ha ingrandita nella schermata principale.

Quindi ... c'è un modo per scoprire la posizione di una finestra ingrandita (preferibilmente nelle stesse unità logiche delle proprietà Superiore e Sinistra)?

risposta

0

Mi rendo conto che si sta lavorando in WPF e questa risposta utilizza la tecnologia Forms, ma dovrebbe funzionare senza troppe difficoltà.

È possibile ottenere una raccolta degli schermi tramite My.Settings.Screens.AllScreens. Da lì puoi accedere alla risoluzione su cui sta lavorando lo schermo.

Dal finestre WPF mantengono i valori superiore/sinistro che avevano quando sono stati massimizzati, allora è possibile determinare quale schermo sono su per capire quale schermo che coordina Top/Sinistra si riferiscono a, e quindi ottenere la parte superiore/sinistra coordinare per quella schermata.

Purtroppo, sono in viaggio e non posso testarlo al momento. Se lo realizzi, mi piacerebbe vedere cosa ti viene in mente.

7

ho finalmente trovato una soluzione che lavora per me: (grazie)

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

Penso che se si modifica la chiamata 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))); questo lo aggiusterà Hai bisogno di ottenere il centro della finestra, non il triangolo, perché questo è il punto che WPF usa per determinare a quale finestra massimizzare, se la finestra è su più di un monitor. – Matt

+1

buona idea, ma in realtà questo aiuta? questo ramo della clausola if viene usato solo quando WindowState è Massimizzato, quindi ActualWith e -Height riguarderanno le dimensioni dello schermo, non il windowsize (ripristinato) – eFloh

+0

Sì, ho capito cosa stai dicendo. è possibile ottenere la dimensione della finestra ripristinata da RestoreBounds e quindi utilizzare quella invece di ActualWidth/ActualHeight? – Matt

6

Ecco la soluzione mi è venuta in base a precedente discussione qui.

Questa soluzione ...

  • restituisce la posizione di una finestra nel suo stato attuale
  • gestisce tutti gli stati di finestra (ingrandita, ridotta a icona, restaurata)
  • non dipende in Windows Form (ma è ispirato da esso)
  • utilizza l'handle di finestra per determinare in modo affidabile il monitor corretto

il meth principale od GetAbsolutePosition è implementato qui come metodo di estensione. Se si dispone di un Window chiamato myWindow, chiamare in questo modo:

Point p = myWindow.GetAbsolutePosition(); 

Ecco il codice 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

Questa dovrebbe essere la soluzione accettata. Grazie! –

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

Riccioli d'oro! La prima soluzione era compatta ma sbagliata, la seconda probabilmente aveva ragione, ma non era compatta. Questo è giusto :) Per qualche motivo i 3 sono votati in ordine inverso rispetto al loro valore reale. –

+0

Non mi dà la risposta giusta per me – Epirocks

3

universale una riga risposta a lavorare per tutti i monitor e tutti di alta DPI varianti:

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

Questo ad esempio restituisce (-8, -8) per una finestra che è massimizzata o n uno schermo ampio 1920 il cui ActualWidth restituisce 1936.

Solo un rant alle altre risposte: Non scambiare mai logici 96 dpi pixel WPF (utilizzando double) con i pixel reali nativi (utilizzando int) - in particolare da solo colata doppia a int!

+0

Ovviamente non funziona su più configurazioni di monitor. – Kilazur

+0

@Kilazur perché ovviamente? L'ho inizialmente testato su una testina tripla su tutti e tre i monitor. La barra delle applicazioni è verticale e non sullo schermo principale, che da solo impazzisce il 50% di tutto il software. – springy76

+1

Il punto (0,0) si trova all'interno dell'area client della finestra e non restituisce l'angolo superiore/sinistro effettivo della cornice della finestra. Se si tenta di utilizzare queste coordinate per posizionare qualcos'altro, viene fuori sbagliato. –

Problemi correlati