Set chiều dài và chiều rộng cho chế độ maximized của window chưa full phần màn hình làm việc

Màn hình của máy em có kích thước 1920x1080; trừ đi cái taskbar thì còn 1920x1030
Chuyện là WPF có cái chế độ maximized cho WindowStyle = None là full màn hình (lấp cả taskbar)
Nhưng em muốn cái window của em khi phóng to không lấp taskbar, thế là em tham khảo trên mạng có người có cái giải pháp. Rồi em copy về vọc thử, kết quả là nó không full phần màn hình làm việc (phần màn hình trừ đi taskbar).
Không phải em kể công chứ dù là em copy về em vẫn vọc xem phương thức nó vận hành (khỏi có mấy bác nói ăn sẵn trên mạng mà ko biết cái j), rồi tiến hành sửa thử nhưng rồi nhận ra là nó vận hành đúng, chỉ tại cái máy mình nó sao sao :v

Đầy đủ Window1.xaml
<Window x:Class="WindowsApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WindowsApplication1" Height="300" Width="300"
	WindowStyle="None"
    >
    <StackPanel>
        <Rectangle Height="30" Fill="BlueViolet" PreviewMouseLeftButtonDown="Rectangle_PreviewMouseLeftButtonDown"></Rectangle>
        <TextBlock Name="WndHeight" FontSize="20"></TextBlock>
    </StackPanel>
</Window>
Đầy đủ Window1.xaml.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using WinInterop=System.Windows.Interop;
using System.Runtime.InteropServices;


namespace WindowsApplication1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>

    public partial class Window1 : Window
    {

        public Window1()
        {
            InitializeComponent();

            Loaded += new RoutedEventHandler(win_Loaded);
            SourceInitialized += new EventHandler(win_SourceInitialized);
            
        }
        void win_SourceInitialized(object sender, EventArgs e)
        {
            System.IntPtr handle = (new WinInterop.WindowInteropHelper(this)).Handle;
            WinInterop.HwndSource.FromHwnd(handle).AddHook(new WinInterop.HwndSourceHook(WindowProc));
        }


        private static System.IntPtr WindowProc(
              System.IntPtr hwnd,
              int msg,
              System.IntPtr wParam,
              System.IntPtr lParam,
              ref bool handled)
        {
            switch (msg)
            {
                case 0x0024:
                    WmGetMinMaxInfo(hwnd, lParam);
                    handled = true;
                    break;
            }

            return (System.IntPtr)0;
        }

        private static void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam)
        {

            MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));

            // Adjust the maximized size and position to fit the work area of the correct monitor
            int MONITOR_DEFAULTTONEAREST = 0x00000002;
            System.IntPtr monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);

            if (monitor != System.IntPtr.Zero)
            {

                MONITORINFO monitorInfo = new MONITORINFO();
                GetMonitorInfo(monitor, monitorInfo);
                RECT rcWorkArea = monitorInfo.rcWork;
                RECT rcMonitorArea = monitorInfo.rcMonitor;
                mmi.ptMaxPosition.x = 0/*Math.Abs(rcWorkArea.left - rcMonitorArea.left)*/;
                mmi.ptMaxPosition.y = 0/*Math.Abs(rcWorkArea.top - rcMonitorArea.top)*/;
                mmi.ptMaxSize.x = 1920/*Math.Abs(rcWorkArea.right - rcWorkArea.left)*/;
                mmi.ptMaxSize.y = 1030/*Math.Abs(rcWorkArea.bottom - rcWorkArea.top)*/;
                //MessageBox.Show("mmi.ptMaxPosition.x = " + Math.Abs(rcWorkArea.left - rcMonitorArea.left) + ";\n mmi.ptMaxPosition.y = " + Math.Abs(rcWorkArea.top - rcMonitorArea.top) + ";\n mmi.ptMaxSize.x = " + Math.Abs(rcWorkArea.right - rcWorkArea.left) + ";\n mmi.ptMaxSize.y = " + Math.Abs(rcWorkArea.bottom - rcWorkArea.top) + ";");
            }

            Marshal.StructureToPtr(mmi, lParam, true);
        }


        /// <summary>
        /// POINT aka POINTAPI
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            /// <summary>
            /// x coordinate of point.
            /// </summary>
            public int x;
            /// <summary>
            /// y coordinate of point.
            /// </summary>
            public int y;

            /// <summary>
            /// Construct a point of coordinates (x,y).
            /// </summary>
            public POINT(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MINMAXINFO
        {
            public POINT ptReserved;
            public POINT ptMaxSize;
            public POINT ptMaxPosition;
            public POINT ptMinTrackSize;
            public POINT ptMaxTrackSize;
        };

        void win_Loaded(object sender, RoutedEventArgs e)
        {
            WindowState = WindowState.Maximized;
        }


        /// <summary>
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public class MONITORINFO
        {
            /// <summary>
            /// </summary>            
            public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));

            /// <summary>
            /// </summary>            
            public RECT rcMonitor = new RECT();

            /// <summary>
            /// </summary>            
            public RECT rcWork = new RECT();

            /// <summary>
            /// </summary>            
            public int dwFlags = 0;
        }


        /// <summary> Win32 </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct RECT
        {
            /// <summary> Win32 </summary>
            public int left;
            /// <summary> Win32 </summary>
            public int top;
            /// <summary> Win32 </summary>
            public int right;
            /// <summary> Win32 </summary>
            public int bottom;

            /// <summary> Win32 </summary>
            public static readonly RECT Empty = new RECT();

            /// <summary> Win32 </summary>
            public int Width
            {
                get { return Math.Abs(right - left); }  // Abs needed for BIDI OS
            }
            /// <summary> Win32 </summary>
            public int Height
            {
                get { return bottom - top; }
            }

            /// <summary> Win32 </summary>
            public RECT(int left, int top, int right, int bottom)
            {
                this.left = left;
                this.top = top;
                this.right = right;
                this.bottom = bottom;
            }


            /// <summary> Win32 </summary>
            public RECT(RECT rcSrc)
            {
                this.left = rcSrc.left;
                this.top = rcSrc.top;
                this.right = rcSrc.right;
                this.bottom = rcSrc.bottom;
            }

            /// <summary> Win32 </summary>
            public bool IsEmpty
            {
                get
                {
                    // BUGBUG : On Bidi OS (hebrew arabic) left > right
                    return left >= right || top >= bottom;
                }
            }
            /// <summary> Return a user friendly representation of this struct </summary>
            public override string ToString()
            {
                if (this == RECT.Empty) { return "RECT {Empty}"; }
                return "RECT { left : " + left + " / top : " + top + " / right : " + right + " / bottom : " + bottom + " }";
            }

            /// <summary> Determine if 2 RECT are equal (deep compare) </summary>
            public override bool Equals(object obj)
            {
                if (!(obj is Rect)) { return false; }
                return (this == (RECT)obj);
            }

            /// <summary>Return the HashCode for this struct (not garanteed to be unique)</summary>
            public override int GetHashCode()
            {
                return left.GetHashCode() + top.GetHashCode() + right.GetHashCode() + bottom.GetHashCode();
            }


            /// <summary> Determine if 2 RECT are equal (deep compare)</summary>
            public static bool operator ==(RECT rect1, RECT rect2)
            {
                return (rect1.left == rect2.left && rect1.top == rect2.top && rect1.right == rect2.right && rect1.bottom == rect2.bottom);
            }

            /// <summary> Determine if 2 RECT are different(deep compare)</summary>
            public static bool operator !=(RECT rect1, RECT rect2)
            {
                return !(rect1 == rect2);
            }


        }

        [DllImport("user32")]
        internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);

        ///// <summary>
        ///// 
        /// </summary>
        [DllImport("User32")]
        internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);

        private void Rectangle_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //DragMove();

            WndHeight.Text = "height x width: " + (Height * 1.25) + " x " + (Width * 1.25) + "\n actual height x width: " + (ActualHeight * 1.25) + " x " + (ActualWidth * 1.25) + "\n screen height x width: " + (SystemParameters.VirtualScreenHeight * 1.25) + " x " + (SystemParameters.VirtualScreenWidth * 1.25);
        }
    }
}
Chỗ code cần lưu tầm (dành cho mấy bác nhác đọc :v)
private static void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam)
        {

            MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));

            // Adjust the maximized size and position to fit the work area of the correct monitor
            int MONITOR_DEFAULTTONEAREST = 0x00000002;
            System.IntPtr monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);

            if (monitor != System.IntPtr.Zero)
            {

                MONITORINFO monitorInfo = new MONITORINFO();
                GetMonitorInfo(monitor, monitorInfo);
                RECT rcWorkArea = monitorInfo.rcWork;
                RECT rcMonitorArea = monitorInfo.rcMonitor;
                mmi.ptMaxPosition.x = 0/*Math.Abs(rcWorkArea.left - rcMonitorArea.left)*/;
                mmi.ptMaxPosition.y = 0/*Math.Abs(rcWorkArea.top - rcMonitorArea.top)*/;
                mmi.ptMaxSize.x = 1920/*Math.Abs(rcWorkArea.right - rcWorkArea.left)*/;
                mmi.ptMaxSize.y = 1030/*Math.Abs(rcWorkArea.bottom - rcWorkArea.top)*/;
                //MessageBox.Show("mmi.ptMaxPosition.x = " + Math.Abs(rcWorkArea.left - rcMonitorArea.left) + ";\n mmi.ptMaxPosition.y = " + Math.Abs(rcWorkArea.top - rcMonitorArea.top) + ";\n mmi.ptMaxSize.x = " + Math.Abs(rcWorkArea.right - rcWorkArea.left) + ";\n mmi.ptMaxSize.y = " + Math.Abs(rcWorkArea.bottom - rcWorkArea.top) + ";");
            }

            Marshal.StructureToPtr(mmi, lParam, true);
        }

Không hiểu sao dù em cho cái kích thước là 1920x1030 (mmi.ptMaxSize.xmmi.ptMaxSize.y) thì nó như thế này

Ảnh minh họa 1

Và em sửa thành 1934x1037 thì vừa khít màn hình (thực ra thì em còn phải set mmi.ptMaxPosition.x về -7)

Ảnh minh họa 2

Mấy bác nào biết thì giúp em với T_T

1 Like

Có phải là Window border???

1 Like

chắc là do cái ResizeMode này: https://docs.microsoft.com/en-us/dotnet/api/system.windows.window.resizemode?view=netframework-4.7.2

thử sửa lại file .xaml:

<Window x:Class="WindowsApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WindowsApplication1" Height="300" Width="300"
    WindowStyle="None"
    ResizeMode="NoResize">

Cách khác vẫn cho Resize window: thêm AllowsTransparency=“True”: https://stackoverflow.com/questions/611298/how-to-create-a-wpf-window-without-a-border-that-can-be-resized-via-a-grip-only

<Window x:Class="WindowsApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WindowsApplication1" Height="300" Width="300"
    WindowStyle="None"
    AllowsTransparency="True"
    ResizeMode="CanResizeWithGrip">
4 Likes

^^ Đúng là cao nhân :slight_smile:

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?