WPF : Maximize window with WindowState Problem (application will hide windows taskbar)
Asked Answered
N

8

23

I have set my main window state to "Maximized" but the problem is my application will fill the whole screen even task bar. what am i doing wrong ? I'm using windows 2008 R2 with resolution : 1600 * 900

Here is the Xaml :

<Window x:Class="RadinFarazJamAutomationSystem.wndMain"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:local="clr-namespace:RadinFarazJamAutomationSystem"
     xmlns:mwt="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
    Title="MyName"  FontFamily="Tahoma" FontSize="12" Name="mainWindow"  WindowState="Maximized"   xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
    xmlns:my="clr-namespace:RadinFarazJamAutomationSystem.Calendare.UC" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  Loaded="mainWindow_Loaded" FlowDirection="LeftToRight"
    ResizeMode="NoResize" Closed="mainWindow_Closed">
Noncommittal answered 31/7, 2011 at 15:49 Comment(0)
M
52

You can set the MaxHeight property of that window to SystemParameters.MaximizedPrimaryScreenHeight using the constructor.

public MainWindow()
{
    InitializeComponent();
    this.MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
}
Marleah answered 31/7, 2011 at 16:11 Comment(3)
You might encounter issues when you have more than one monitor hooked up to your computer.Hedger
When you have a more than one monitor. Instead of SystemParameters.MaximizedPrimaryScreenHeight use SystemParameters.MaximumWindowTrackHeight;Grain
I tried this and the bottom part of my window is hidden behind the task bar.Manoeuvre
H
23

To continue with my previous remark. I use the following code in my applications (source: Maximizing WPF windows

using WinInterop = System.Windows.Interop;
using System.Runtime.InteropServices;

    public MainWindow()
    {
        InitializeComponent();
        winMain.SourceInitialized += new EventHandler(win_SourceInitialized);
    }


    #region Avoid hiding task bar upon maximalisation

    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;
    }

    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 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 = Math.Abs(rcWorkArea.left - rcMonitorArea.left);
            mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.top - rcMonitorArea.top);
            mmi.ptMaxSize.x = Math.Abs(rcWorkArea.right - rcWorkArea.left);
            mmi.ptMaxSize.y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top);
        }

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

    [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)
    {
        winMain.WindowState = WindowState.Maximized;
    }

    [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;
    }

    [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);

    [DllImport("user32.dll")]
    static extern bool GetCursorPos(ref Point lpPoint);

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

    #endregion
Hedger answered 10/11, 2011 at 16:26 Comment(4)
This approach makes MinWidth & MinHeight useless.Narton
To solve that, you must set handled = false in case 0x0024Narton
I am using this code, Its working fine if both monitors are of same resolution or Primary monitor is of larger size. If I set the monitor with lower resolution(1360*768) as Primary, than Secondary monitor(1920*1080), And maximize the window on Secondary then it exceeds the width of the Secondary and only border can be seen on the Primary. Any idea?Subvention
I set mmi.ptMaxTrackSize.x = Math.Abs(workArea.Width); mmi.ptMaxTrackSize.y = Math.Abs(workArea.Height); to solve in WmGetMinMaxInfo method.Subvention
M
7

I simplified Geoffrey's answer a bit so you don't have to p/invoke anything.

    public MainWindow()
    {
        InitializeComponent();
        winMain.SourceInitialized += new EventHandler(win_SourceInitialized);
    }

    void win_SourceInitialized( object sender, System.EventArgs e )
    {
        var handle = (new WindowInteropHelper( _attachedElement )).Handle;
        var handleSource = HwndSource.FromHwnd( handle );
        if ( handleSource == null )
            return;
        handleSource.AddHook( WindowProc );
    }

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

        return (IntPtr)0;
    }

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

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

        // Adjust the maximized size and position to fit the work area of the correct monitor
        var currentScreen = System.Windows.Forms.Screen.FromHandle( hwnd );
        var workArea = currentScreen.WorkingArea;
        var monitorArea = currentScreen.Bounds;
        mmi.ptMaxPosition.x = Math.Abs( workArea.Left - monitorArea.Left );
        mmi.ptMaxPosition.y = Math.Abs( workArea.Top - monitorArea.Top );
        mmi.ptMaxSize.x = Math.Abs( workArea.Right - workArea.Left );
        mmi.ptMaxSize.y = Math.Abs( workArea.Bottom - workArea.Top );

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


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

[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;
    }
}
Madras answered 19/8, 2014 at 20:26 Comment(1)
implementing Window.Form.Screen is problematic here for WPF. Not really the ideal solution. Geoffrey's solution is perfectly fine for me. Worked exactly as expected - it helps to avoid the taskbar hidding the footer of my application when it is in "Maximum" size mode.Stacked
C
6

This one works the best...

public MainWindow()
    {
        InitializeComponent();
        MaxHeight = SystemParameters.VirtualScreenHeight;
        MaxWidth = SystemParameters.VirtualScreenWidth;
    }
Cyme answered 13/1, 2020 at 0:5 Comment(1)
Some applications may require that you subtract about 10 pixels from each dimension to prevent overlapping of the taskbar and "off-screen" areas. But this is by far the best approach.Heartwarming
G
4

I've implemented solution which considers multiple displays case based on the Mike Weinhardt answer in the thread. If you want to maximize/minimize window programmatically with your own buttons you can use this.

Solution:

// To get a handle to the specified monitor
[DllImport("user32.dll")]
private static extern IntPtr MonitorFromWindow(IntPtr hwnd, int dwFlags);

// To get the working area of the specified monitor
[DllImport("user32.dll")]
private static extern bool GetMonitorInfo(HandleRef hmonitor, [In, Out] MonitorInfoEx monitorInfo);

private static MonitorInfoEx GetMonitorInfo(Window window, IntPtr monitorPtr) {
    var monitorInfo = new MonitorInfoEx();

    monitorInfo.cbSize = Marshal.SizeOf(monitorInfo);
    GetMonitorInfo(new HandleRef(window, monitorPtr), monitorInfo);

    return monitorInfo;
}

private static void Minimize(Window window) {
     if(window == null) {
         return;
     }

     window.WindowState = WindowState.Minimized;
 }

 private static void Restore(Window window) {
        if(window == null) {
            return;
        }

        window.WindowState = WindowState.Normal;
        window.ResizeMode = ResizeMode.CanResizeWithGrip;
    }

    private static void Maximize(Window window) {
        window.ResizeMode = ResizeMode.NoResize;

        // Get handle for nearest monitor to this window
        var wih = new WindowInteropHelper(window);

        // Nearest monitor to window
        const int MONITOR_DEFAULTTONEAREST = 2;
        var hMonitor = MonitorFromWindow(wih.Handle, MONITOR_DEFAULTTONEAREST);

        // Get monitor info
        var monitorInfo = GetMonitorInfo(window, hMonitor);

        // Create working area dimensions, converted to DPI-independent values
        var source = HwndSource.FromHwnd(wih.Handle);

        if(source?.CompositionTarget == null) {
            return;
        }

        var matrix = source.CompositionTarget.TransformFromDevice;
        var workingArea = monitorInfo.rcWork;

        var dpiIndependentSize =
            matrix.Transform(
                new Point(workingArea.Right - workingArea.Left,
                          workingArea.Bottom - workingArea.Top));



        // Maximize the window to the device-independent working area ie
        // the area without the taskbar.
        window.Top = workingArea.Top;
        window.Left = workingArea.Left;

        window.MaxWidth = dpiIndependentSize.X;
        window.MaxHeight = dpiIndependentSize.Y;

        window.WindowState = WindowState.Maximized;
    }

Auxilary structs:

// Rectangle (used by MONITORINFOEX)
[StructLayout(LayoutKind.Sequential)]
public struct Rect {
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}

// Monitor information (used by GetMonitorInfo())
[StructLayout(LayoutKind.Sequential)]
public class MonitorInfoEx {
    public int cbSize;
    public Rect rcMonitor; // Total area
    public Rect rcWork; // Working area
    public int dwFlags;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
    public char[] szDevice;
}

p.s. to hide default buttons use:

WindowStyle="None"

in the window XAML.

Gehrke answered 23/4, 2021 at 11:6 Comment(1)
So far this works best for me, height is just about the top of the taskbar, and work on multiple displays too. Literally just like a normal window.Heron
N
1

You can set MaxHeight property in the xaml code, like that:

 MaxHeight="{x:Static SystemParameters.MaximizedPrimaryScreenHeight}"
Neile answered 25/11, 2020 at 15:7 Comment(1)
Works but not the best solution. Part of the application footer is still hidding behind the taskbar. Geoffrey's solution is the best here. Also, maximizing the secondary screen doesn't work as expected. The application jumps to the primary screen (monitor) when maximized. Unfortunnately, this would have been the easiert and cleanest solution if not for that problem.Stacked
U
0

I wanted the opposite (with WindowStyle=None), but reversing this solution also works for your case:

// prevent it from overlapping the taskbar

// "minimize" it
WindowStyle = WindowStyle.SingleBorderWindow;
// Maximize it again. This time it will respect the taskbar.
WindowStyle = WindowStyle.None;
WindowState = WindowState.Maximized;
// app is now borderless fullscreen, showing the taskbar again

What I did for my case:

// make it always overlap the taskbar

// From windowed to maximized without border and window bar
WindowStyle = WindowStyle.None;
WindowState = WindowState.Maximized;
// Now the window does not overlap the taskbar
Hide();
Show();
// Now it does (because it's re-opened)
Urbanus answered 12/4, 2019 at 13:36 Comment(0)
H
0

I added the code suggested by AmanViridi to fix the issue of different monitor resolutions to chrislarson's answer of Geoffrey's answer

    public MainWindow()
    {
        InitializeComponent();
        winMain.SourceInitialized += new EventHandler(win_SourceInitialized);
    }

    void win_SourceInitialized( object sender, System.EventArgs e )
    {
        var handle = (new WindowInteropHelper( _attachedElement )).Handle;
        var handleSource = HwndSource.FromHwnd( handle );
        if ( handleSource == null )
            return;
        handleSource.AddHook( WindowProc );
    }

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

        return (IntPtr)0;
    }

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

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

        // Adjust the maximized size and position to fit the work area of the correct monitor
        var currentScreen = System.Windows.Forms.Screen.FromHandle( hwnd );
        var workArea = currentScreen.WorkingArea;
        var monitorArea = currentScreen.Bounds;
        mmi.ptMaxPosition.x = Math.Abs( workArea.Left - monitorArea.Left );
        mmi.ptMaxPosition.y = Math.Abs( workArea.Top - monitorArea.Top );
        mmi.ptMaxSize.x = Math.Abs( workArea.Right - workArea.Left );
        mmi.ptMaxSize.y = Math.Abs( workArea.Bottom - workArea.Top );
        mmi.ptMaxTrackSize.x = Math.Abs(workArea.Width);
        mmi.ptMaxTrackSize.y = Math.Abs(workArea.Height);

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


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

[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;
    }
}
Hebraist answered 24/5, 2023 at 8:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.