2011-01-26 20 views
11

私は最大化されたウィンドウの位置を知る必要があります。最大化されたウィンドウの位置を見つけるにはどうすればよいですか?

WPFウィンドウには、ウィンドウの位置を指定するTopおよびLeftプロパティがあります。ただし、ウィンドウを最大化すると、これらのプロパティはウィンドウの値を通常の状態に保ちます。

1画面設定で実行している場合、最大位置は自然(0,0)です。しかし、必ずしも真ではない複数の画面がある場合。メイン画面で最大化されている場合は、ウィンドウの位置は(0,0)になります。

だから、最大化されたウィンドウの位置を知る方法はありますか?(好ましくは、TopプロパティとLeftプロパティと同じ論理単位で)

答えて

0

私はあなたがWPFで作業していることを認識しています。この回答はFormsテクノロジを使用していますが、それほど問題はありません。

My.Settings.Screens.AllScreensを通じて画面のコレクションを取得できます。そこから、画面が現在作業している解像度にアクセスできます。

WPFウィンドウでは、最大化されたときのTop/Left値が保持されるため、Top/Left座標がどの画面を参照しているかを把握して、その画面の座標。

残念ながら、私は道を歩いており、現時点ではこれをテストすることはできません。あなたが実装するなら、私はあなたが思いつくものを見たいと思っています。

7

私は最終的に私のために働いて解決策を見つけた:

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

GetWorkingArea呼び出しを次のように変更すると、私は思う:windowRectangle = System.Windows.Forms.Screen.GetWorkingArea(新しいSystem.Drawing.Point(int)window.Left +(int)(window.ActualWidth/2) (int)window.op +(int)(window.ActualHeight/2)));それはそれを修正します。ウィンドウが複数のモニタにまたがっている場合、WPFが最大化するウィンドウを決定するために使用するポイントなので、ウィンドウの中心を取得する必要があります。 – Matt

+1

良いアイデアだが、これは実際に助けになるのだろうか?この句のこの枝は、WindowStateが最大化されている場合にのみ使用されるため、ActualWithと-Heightは(復元された)ウィンドウサイズではなく画面サイズになります。 – eFloh

+0

ええ、私はあなたが言っていることを得ています。あなたRestoreBoundsから復元されたウィンドウサイズを取得し、おそらくActualWidth/ActualHeightの代わりに使用することはできますか? – Matt

6

ここで私はここに以前の議論(!ありがとう)に基づいて思い付いたソリューションです。

このソリューション...

  • は、すべてのウィンドウ状態を扱う
  • 現在の状態でウィンドウの位置を返します(最大化、最小化、復元)
  • Windowsフォームに依存しない(ただし、
  • を確実に正しいモニター

を主メタを決定するために、ウィンドウハンドルを使用して)、それに触発されod GetAbsolutePositionは、ここでは拡張メソッドとして実装されています。あなたはmyWindowと呼ばれるWindowを持っている場合は、このようにそれを呼び出す:

Point p = myWindow.GetAbsolutePosition(); 

ここでは完全なコードです:すべてのモニターおよびすべての高DPIの変種のために働いて

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

これは容認された解決策であるべきです。ありがとう! –

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

ゴールドロック!最初の解決策はコンパクトでしたが、間違っていました。これはちょうどいいです:)何らかの理由で3は、実際の値の逆の順序で投票されます。 –

+0

私には正解があまりありません – Epirocks

3

ユニバーサル1行の答え:

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

これは、たとえば、最大化されたウィンドウに対して(-8、-8)を返します。 nは1920ワイドスクリーンで、ActualWidthは1936を返します。

ネイティブの実ピクセル(intを使用)と論理96dpi WPFピクセル(doubleを使用)を混ぜて使用しないでください。特にdoubleをintにキャストするだけです。

+0

明らかに、複数のモニター設定では機能しません。 – Kilazur

+0

@Kilazurなぜ明らかに?私は最初、これを3つのモニターすべてでトリプルヘッドでテストしました。タスクバーは垂直で、プライマリ画面ではなく、すべてのソフトウェアの50%を占めています。 – springy76

+1

ポイント(0,0)はウィンドウのクライアント領域の内側にあり、ウィンドウフレームの実際の左上隅を返しません。これらの座標を使用して別の場所に配置しようとすると、間違ったものになります。 –

関連する問題