如何找到最大化窗口的位置?

haa*_*gel 13 wpf window

我需要知道最大化窗口的位置.

WPF窗口具有Top和Left属性,用于指定窗口的位置.但是,如果最大化窗口,这些属性会使窗口的值保持正常状态.

如果您在单屏设置上运行,则最大化位置自然是(0,0).但是,如果您有多个屏幕不一定是真的.如果在主屏幕上最大化窗口,窗口将只有位置(0,0).

那么......有没有办法找出最大化窗口的位置(最好是与Top和Left属性相同的逻辑单元)?

tgr*_*r42 10

这是我根据之前的讨论提出的解决方案(谢谢!).

这解决方案......

  • 返回当前状态的窗口位置
  • 处理所有窗口状态(最大化,最小化,恢复)
  • 不依赖于Windows Forms(但受其启发)
  • 使用窗口句柄可靠地确定正确的监视器

GetAbsolutePosition这里实现的主要方法是扩展方法.如果你有一个Window被叫myWindow,请这样称呼它:

Point p = myWindow.GetAbsolutePosition();
Run Code Online (Sandbox Code Playgroud)

这是完整的代码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的解决方案。谢谢! (2认同)

eFl*_*loh 6

我终于找到了一个适合我的解决方案:

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 我想如果你将GetWorkingArea调用更改为:windowRectangle = System.Windows.Forms.Screen.GetWorkingArea(new System.Drawing.Point((int)window.Left +(int)(window.ActualWidth/2),(int) window.Top +(int)(window.ActualHeight/2))); 这将解决它.您需要获取窗口的中心,而不是topleft,因为如果窗口跨越多个监视器,那么WPF用于确定最大化窗口的点. (2认同)

Mik*_*ord 6

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 金发姑娘!第一个解决方案是紧凑的,但错误的,第二个解决方案可能是正确的,但不是紧凑的。这是正确的:)出于某种原因,以相反的顺序对3进行了投票。 (2认同)

spr*_*y76 6

通用的一线应答适用于所有显示器和所有高DPI变体:

Point leftTop = this.PointToScreen(new Point(0, 0));
Run Code Online (Sandbox Code Playgroud)

例如,这返回(-8,-8)窗口,该窗口在1920宽屏幕上最大化,其ActualWidth返回1936.

只是一个夸夸其谈的其他答案:千万别把逻辑96个dpi的WPF像素(使用double)与本地实际像素(使用int) -特别是刚刚铸造双为int!


Cod*_*ior 0

我知道您正在使用 WPF,并且这个答案使用了表单技术,但它应该没有太大困难。

您可以通过 My.Settings.Screens.AllScreens 获取屏幕的集合。从那里您可以访问屏幕当前正在使用的分辨率。

由于 WPF 窗口保留最大化时的上/左值,因此您可以通过确定上/左坐标引用的屏幕来确定它们位于哪个屏幕上,然后获取该屏幕的上/左坐标。

不幸的是,我正在路上,目前无法对此进行测试。如果你真的实施了,我很想看看你能想出什么。