How can I find the position of a maximized window?

前端 未结 7 1543
走了就别回头了
走了就别回头了 2020-12-30 05:23

I need to know the position of a window that is maximized.

WPF Window has Top and Left properties that specifies the window\'s location. However, if you maximize the

相关标签:
7条回答
  • 2020-12-30 05:40

    I realize that you are working in WPF, and this answer makes use of Forms technology, but it should work without much difficulty.

    You can get a collection of the screens through My.Settings.Screens.AllScreens. From there you can access the resolution that the screen is currently working on.

    Since WPF windows retain the Top/Left values that they had when they were maximized, then you can determine which screen they are on by figuring out which screen that Top/Left coordinates refer to, and then get the top/left coordinate for that screen.

    Unfortunately, I am on the road, and can't test this at the moment. If you do implement, I would love to see what you come up with.

    0 讨论(0)
  • 2020-12-30 05:43

    Here's the solution I came up with based on previous discussion here (thanks!).

    This solution...

    • returns the position of a window in its current state
    • handles all window states (maximized, minimized, restored)
    • does not depend on Windows Forms (but is inspired by it)
    • uses the window handle to reliably determine the correct monitor

    The main method GetAbsolutePosition is implemented here as an extension method. If you have a Window called myWindow, call it like this:

    Point p = myWindow.GetAbsolutePosition();
    

    Here's the complete code:

    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);
        }
    }
    
    0 讨论(0)
  • 2020-12-30 05:46

    I finally found a solution working for me:

    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;
    }
    
    0 讨论(0)
  • 2020-12-30 05:57

    Universal one line answer working for all monitors and all high DPI variants:

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

    This for example returns (-8, -8) for a window which is maximized on a 1920 wide screen whose ActualWidth returns 1936.

    Just a rant to the other answers: NEVER mix up logical 96 dpi WPF pixels (using double) with native real pixels (using int) - especially by just casting double to int!

    0 讨论(0)
  • 2020-12-30 06:04
    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 讨论(0)
  • 2020-12-30 06:04

    This seems to be a problem with System.Windows.Window!!!

    Maximized window give unreliable values for Left, Width, ActualWidth, Top, Height and ActualHeight.

    After maximizing a window, it can often keep the Left and Width values from the pre-maximized window.

    For others reading - there is no problem when the window is un-maximized.

    Also, what I find odd is that the values you read are in WPF DPI coordinates, [i.e. 1936x1096, from (-8, -8) to (1928, 1088)], but when you set these values you have to use screen pixel coordinates, [i.e. 1920x1080, using (0,0) etc...]

    @tgr provided a reliable partial solution above, which I've improved below:

    • Fixing intellisense for extension methods by moving helper class to sub class
    • creating GetAbsoluteRect() method to provide Width/Height and point all in one call
    • refactoring common code

    Here's the C# solution:

    using System;
    using System.Runtime.InteropServices;
    using System.Windows;
    using System.Windows.Interop;
    
    public static partial class Extensions
    {
        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 Int32Rect _getOsInteropRect(Window w)
        {
            bool multimonSupported = OSInterop.GetSystemMetrics(OSInterop.SM_CMONITORS) != 0;
            if (!multimonSupported)
            {
                OSInterop.RECT rc = new OSInterop.RECT();
                OSInterop.SystemParametersInfo(48, 0, ref rc, 0);
                return new Int32Rect(rc.left, rc.top, rc.width, rc.height);
            }
    
            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);
            return new Int32Rect(info.rcWork.left, info.rcWork.top, info.rcWork.width, info.rcWork.height);
        }
    
        public static Rect GetAbsoluteRect(this Window w)
        {
            if (w.WindowState != WindowState.Maximized)
                return new Rect(w.Left, w.Top, w.ActualWidth, w.ActualHeight);
    
            var r = _getOsInteropRect(w);
            return new Rect(r.X, r.Y, r.Width, r.Height);
        }
    
        public static Point GetAbsolutePosition(this Window w)
        {
            if (w.WindowState != WindowState.Maximized)
                return new Point(w.Left, w.Top);
    
            var r = _getOsInteropRect(w);
            return new Point(r.X, r.Y);
        }
    }
    
    0 讨论(0)
提交回复
热议问题