Borderless window application takes up more space than my screen resolution
Asked Answered
V

9

11

I have created a borderless application in WPF, and it works pretty good. However, when I set the WindowState to full screen, the application takes up more space than my screen resolution, so there are some pixels outside the screen in all directions! (looks like some hard coded negative margins are added to hide the default border)

Any Ideas how to prevent this from happening?

My xaml:

<Window x:Class="MyApp.Shell"
    WindowStyle="None"
    BorderThickness="0"
    AllowsTransparency="True"
    Background="Transparent"
    ResizeMode="CanResizeWithGrip"
    WindowState="{Binding MainApplicationWindowState}"
    ...

Also, another problem I have seen is that the Windows toolbar / taskbar is covered in the fullsize state, so it looks like the "actual" screen height is used and not the "available" screen height, meaning screen height minus the windows toolbar / taskbar!

Anyone found a solution to these issues?

Thanks

Vanish answered 19/1, 2010 at 10:35 Comment(1)
Wow 9 years ago :D Does the Issue only appear when the AllowsTransparency or a WindowChrome is set?Yetta
W
2

I solved the problem this way:

XAML:

WindowStyle="None"
Left="0"
Top="0"
Width="{Binding WPFSettings.Width}"
Height="{Binding WPFSettings.Height}">

Visual Basic:

Public Class WPFSettings
   Public ReadOnly Property Width() As Double
      Get
         Return System.Windows.SystemParameters.PrimaryScreenWidth
      End Get
   End Property

   Public ReadOnly Property Height() As Double
      Get
         Return System.Windows.SystemParameters.PrimaryScreenHeight
      End Get
   End Property
End Class

It works pretty good.

Wynnie answered 19/1, 2010 at 16:15 Comment(2)
Thanks. Will try it out. One issue I see with the PrimaryScreenHeight is when a second monitor is used, but that should be fairly simple to work around! One note; Since you are using Top and Left, what about Bottom and Right? Will they move even further out of the screen?Vanish
Perfect. But for me, it only works if on top of the XAML you posted here, I also set WindowState="Maximized"Saturniid
M
5

I found this great solution

<Window WindowStyle="None" WindowStartupLocation="CenterScreen" WindowState="Maximized"
        MaxWidth="{Binding Source={x:Static SystemParameters.WorkArea}, Path=Width}"
        MaxHeight="{Binding Source={x:Static SystemParameters.WorkArea}, Path=Height}"
    >
...
</Window>

But error for me still persists, windows is offset by few pixels on top and left... I tried to set Left and Top to 0 after I change window state but nothing happens.

Marlanamarlane answered 25/2, 2013 at 14:38 Comment(0)
W
2

I solved the problem this way:

XAML:

WindowStyle="None"
Left="0"
Top="0"
Width="{Binding WPFSettings.Width}"
Height="{Binding WPFSettings.Height}">

Visual Basic:

Public Class WPFSettings
   Public ReadOnly Property Width() As Double
      Get
         Return System.Windows.SystemParameters.PrimaryScreenWidth
      End Get
   End Property

   Public ReadOnly Property Height() As Double
      Get
         Return System.Windows.SystemParameters.PrimaryScreenHeight
      End Get
   End Property
End Class

It works pretty good.

Wynnie answered 19/1, 2010 at 16:15 Comment(2)
Thanks. Will try it out. One issue I see with the PrimaryScreenHeight is when a second monitor is used, but that should be fairly simple to work around! One note; Since you are using Top and Left, what about Bottom and Right? Will they move even further out of the screen?Vanish
Perfect. But for me, it only works if on top of the XAML you posted here, I also set WindowState="Maximized"Saturniid
L
1

Try this

Width="{Binding Source={x:Static SystemParameters.WorkArea}, Path=Width}"
Height="{Binding Source={x:Static SystemParameters.WorkArea}, Path=Height}"
Loggerhead answered 26/3, 2015 at 5:32 Comment(0)
L
1

A newer feature of .NET has solved this problem. Leave your WindowStyle="SingleBorderWindow" or "ThreeDBorderWindow" Leave ResizeMode="CanResize", then add this to the xaml inside the

<Window>
    <WindowChrome.WindowChrome>
        <WindowChrome GlassFrameThickness="0" CornerRadius="0" CaptionHeight="0" 
            UseAeroCaptionButtons="False" ResizeBorderThickness="7" />
    </WindowChrome.WindowChrome>
</Window>

The window will not have any of the default window pane, but will still allow resizing and will not cover the task bar when maximized.

Lemar answered 2/5, 2018 at 15:22 Comment(3)
Doesn't works and when you use a WindowStyle != None AllowTransparency must be false!Yetta
I just tried it with WindowStyle="None" and AllowsTransparency="True" and it works just fine. It allows resizing as if there was a border and when the window is maximized it doesn't cover the start menu. (I tested with .NET 4.7.2, didn't try earlier versions)Lemar
Thanks that's the only solution that worked for me, also using .NET 4.7.2Queenie
E
1

I am pretty late to the club, but I believe someone coming after me may benefit out of it. I tried several solutions but most of them failed to work in multiple displays. So, I am sharing a solution that worked perfectly for me in a commercial application.

I registered SourceInitialized event. And in the callback for the event, I added the following code,

        private void Window_SourceInitialized (object sender, EventArgs e)
        {
        WindowSizing.WindowInitialized(this);
        }

While following is the code for WindowSizing class,

public static class WindowSizing
    {
    const int MONITOR_DEFAULTTONEAREST = 0x00000002;

    #region DLLImports

    [DllImport("shell32", CallingConvention = CallingConvention.StdCall)]
    public static extern int SHAppBarMessage (int dwMessage, ref APPBARDATA pData);

    [DllImport("user32", SetLastError = true)]
    static extern IntPtr FindWindow (string lpClassName, string lpWindowName);

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

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

    #endregion

    private static MINMAXINFO AdjustWorkingAreaForAutoHide (IntPtr monitorContainingApplication, MINMAXINFO mmi)
        {
        IntPtr hwnd = FindWindow("Shell_TrayWnd", null);
        if ( hwnd == null )
            return mmi;
        IntPtr monitorWithTaskbarOnIt = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
        if ( !monitorContainingApplication.Equals(monitorWithTaskbarOnIt) )
            return mmi;
        APPBARDATA abd = new APPBARDATA();
        abd.cbSize = Marshal.SizeOf(abd);
        abd.hWnd = hwnd;
        SHAppBarMessage((int) ABMsg.ABM_GETTASKBARPOS, ref abd);
        int uEdge = GetEdge(abd.rc);
        bool autoHide = System.Convert.ToBoolean(SHAppBarMessage((int) ABMsg.ABM_GETSTATE, ref abd));

        if ( !autoHide )
            return mmi;

        switch ( uEdge )
            {
            case (int) ABEdge.ABE_LEFT:
                mmi.ptMaxPosition.x += 2;
                mmi.ptMaxTrackSize.x -= 2;
                mmi.ptMaxSize.x -= 2;
                break;
            case (int) ABEdge.ABE_RIGHT:
                mmi.ptMaxSize.x -= 2;
                mmi.ptMaxTrackSize.x -= 2;
                break;
            case (int) ABEdge.ABE_TOP:
                mmi.ptMaxPosition.y += 2;
                mmi.ptMaxTrackSize.y -= 2;
                mmi.ptMaxSize.y -= 2;
                break;
            case (int) ABEdge.ABE_BOTTOM:
                mmi.ptMaxSize.y -= 2;
                mmi.ptMaxTrackSize.y -= 2;
                break;
            default:
                return mmi;
            }
        return mmi;
        }

    private static int GetEdge (RECT rc)
        {
        int uEdge = -1;
        if ( rc.top == rc.left && rc.bottom > rc.right )
            uEdge = (int) ABEdge.ABE_LEFT;
        else if ( rc.top == rc.left && rc.bottom < rc.right )
            uEdge = (int) ABEdge.ABE_TOP;
        else if ( rc.top > rc.left )
            uEdge = (int) ABEdge.ABE_BOTTOM;
        else
            uEdge = (int) ABEdge.ABE_RIGHT;
        return uEdge;
        }

    public static void WindowInitialized (Window window)
        {
        IntPtr handle = (new System.Windows.Interop.WindowInteropHelper(window)).Handle;
        System.Windows.Interop.HwndSource.FromHwnd(handle).AddHook(new System.Windows.Interop.HwndSourceHook(WindowProc));
        }

    private static 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 (IntPtr) 0;
        }

    private static void WmGetMinMaxInfo (IntPtr hwnd, IntPtr lParam)
        {
        MINMAXINFO mmi = (MINMAXINFO) Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));
        IntPtr monitorContainingApplication = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);

        if ( monitorContainingApplication != System.IntPtr.Zero )
            {
            MONITORINFO monitorInfo = new MONITORINFO();
            GetMonitorInfo(monitorContainingApplication, 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);
            mmi.ptMaxTrackSize.x = mmi.ptMaxSize.x;                                                 //maximum drag X size for the window
            mmi.ptMaxTrackSize.y = mmi.ptMaxSize.y;                                                 //maximum drag Y size for the window
            mmi.ptMinTrackSize.x = 800;                                                             //minimum drag X size for the window
            mmi.ptMinTrackSize.y = 600;                                                             //minimum drag Y size for the window
            mmi = AdjustWorkingAreaForAutoHide(monitorContainingApplication, mmi);                  //need to adjust sizing if taskbar is set to autohide
            }
        Marshal.StructureToPtr(mmi, lParam, true);
        }

    public enum ABEdge
        {
        ABE_LEFT = 0,
        ABE_TOP = 1,
        ABE_RIGHT = 2,
        ABE_BOTTOM = 3
        }

    public enum ABMsg
        {
        ABM_NEW = 0,
        ABM_REMOVE = 1,
        ABM_QUERYPOS = 2,
        ABM_SETPOS = 3,
        ABM_GETSTATE = 4,
        ABM_GETTASKBARPOS = 5,
        ABM_ACTIVATE = 6,
        ABM_GETAUTOHIDEBAR = 7,
        ABM_SETAUTOHIDEBAR = 8,
        ABM_WINDOWPOSCHANGED = 9,
        ABM_SETSTATE = 10
        }

    [StructLayout(LayoutKind.Sequential)]
    public struct APPBARDATA
        {
        public int cbSize;
        public IntPtr hWnd;
        public int uCallbackMessage;
        public int uEdge;
        public RECT rc;
        public bool lParam;
        }

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

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public class MONITORINFO
        {
        public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));
        public RECT rcMonitor = new RECT();
        public RECT rcWork = new RECT();
        public int dwFlags = 0;
        }

    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
        {
        public int x;
        public int y;

        public POINT (int x, int y)
            {
            this.x = x;
            this.y = y;
            }
        }

    [StructLayout(LayoutKind.Sequential, Pack = 0)]
    public struct RECT
        {
        public int left;
        public int top;
        public int right;
        public int bottom;
        }
    }

This works like a magic for many scenarios, like maximizing the window with no border covers the task bar as well. This solution keeps the taskbar uncovered as well.

Regards, Umar

Excisable answered 26/10, 2021 at 9:30 Comment(1)
This works a treat if you are concerned about render performance with multiple monitors whilst using AllowsTransparency and WindowStyle.None and maximised windows. Lifesaver.Ruberta
B
0

In Xaml set the following binding on the Window.MaxHeight:

MaxHeight="{DynamicResource {x:Static SystemParameters.MaximizedPrimaryScreenHeightKey}}"

No need for an additional utility class.

Bondholder answered 2/9, 2010 at 18:39 Comment(1)
But what if I want to use my application on a second monitor?Vanish
A
0

In my case the XAML tag of the Window had the Property SizeToContent="True" and all I had to do was to remove it.

Aftersensation answered 13/5, 2011 at 10:23 Comment(0)
E
0

I needed this to work across different size displays (like most people it sounds). So I simply did this...

<Window x:Class="MyApp.MainWindow"
    ResizeMode="CanResize" 
    WindowStyle="SingleBorderWindow"
    SizeChanged="Window_SizeChanged">
....
Code
....
</Window>


public void Window_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        if (this.WindowState == WindowState.Maximized)
        {
            this.BorderThickness = new System.Windows.Thickness(8);
        }
        else
        {
            this.BorderThickness = new System.Windows.Thickness(0);
        }
    }
Eyas answered 10/7, 2019 at 8:19 Comment(0)
H
-1

I use a trigger on the window:

<Style.Triggers>
    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Path=WindowState}" Value="{x:Static WindowState.Maximized}">
        <Setter Property="BorderThickness" Value="8"/>
    </DataTrigger>
</Style.Triggers>

this trigger create a Border when the windowstate is Maximized. I think it's useful.

Hupp answered 4/9, 2019 at 2:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.