2
votes

I am developing a WPF application. I completely got rid of the standard windows border and created my own by setting the WindowStyle to None and AllowsTransparency to true. The only problem is that when the window is maximized it fills the entire screen, covering the taskbar. Is there any way to create your own borders without this happening?

3

3 Answers

2
votes

Use method CompatibilityMaximizedNoneWindow.

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;

using Point = System.Drawing.Point;

internal static class WindowExtensions
{
    public static PointF StandartDPI = new PointF(96f, 96f);
    private static PointF? currentDpi = null;
    public static float WidthZoom {get{return CurrentDPI.X/ StandartDPI.X; } }
    public static float HeigthZoom { get { return CurrentDPI.Y / StandartDPI.Y; } }

    public static PointF CurrentDPI
    {
        get
        {
            if (!currentDpi.HasValue)
            {
                var wiHelper = new WindowInteropHelper(App.Current.MainWindow);
                Graphics g = Graphics.FromHwnd(wiHelper.Handle);
                try
                {
                    currentDpi = new PointF(g.DpiX, g.DpiY);
                }
                catch
                {
                    currentDpi = StandartDPI;
                }
                finally
                {
                    g.Dispose();
                }
            }
            return currentDpi.Value;
        }
    }


    public static Window GetWindowFromTemplate(this object templateFrameworkElement)
    {
        var window = ((FrameworkElement)templateFrameworkElement).TemplatedParent as Window;
        return window;
    }

    private static int minWidth;
    private static int minHeight;

    public static void CompatibilityMaximizedNoneWindow(this Window window)
    {
        var wiHelper = new WindowInteropHelper(window);
        minHeight = (int)window.MinHeight;
        minWidth = (int)window.MinWidth;

        var handle = wiHelper.Handle;
        var hwndSource = HwndSource.FromHwnd(handle);
        if (hwndSource != null)
        {
            hwndSource.AddHook(CompatibilityMaximizedNoneWindowProc);
        }
    }

    [DllImport("user32")]
    private static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);[DllImport("user32")]
    private static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
    private 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)]
    private struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }

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

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

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

    private static IntPtr CompatibilityMaximizedNoneWindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        const int WM_GETMINMAXINFO = 0x0024;
        const int MONITOR_DEFAULTTONEAREST = 0x00000002;
        switch (msg)
        {
            case WM_GETMINMAXINFO:
                var mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));
                var monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
                if (monitor != IntPtr.Zero)
                {
                    var monitorInfo = new MONITORINFO();
                    GetMonitorInfo(monitor, monitorInfo);
                    var rcWorkArea = monitorInfo.rcWork;
                    var 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);
                    //Hack для ограничения минимальных размеров окна
                    mmi.ptMinTrackSize.x = (int)(minWidth*WidthZoom);
                    mmi.ptMinTrackSize.y = (int)(minHeight*HeigthZoom);
                    //Hack для нормальной работы всплывающей панели задач
                    var taskbar = new TaskbarInfo();
                    if (taskbar.AutoHide)
                    {
                        switch (taskbar.Position)
                        {
                            case TaskbarInfo.TaskbarPosition.Top:
                                mmi.ptMaxPosition.y++;
                                mmi.ptMaxSize.y--;
                                break;
                            case TaskbarInfo.TaskbarPosition.Bottom:
                                mmi.ptMaxPosition.y--;
                                mmi.ptMaxSize.y--;
                                break;
                            case TaskbarInfo.TaskbarPosition.Left:
                                mmi.ptMaxPosition.x++;
                                mmi.ptMaxSize.x--;
                                break;
                            case TaskbarInfo.TaskbarPosition.Right:
                                mmi.ptMaxPosition.x--;
                                mmi.ptMaxSize.x--;
                                break;
                        }
                    }
                }
                Marshal.StructureToPtr(mmi, lParam, true); handled = true; break;
        }
        return (IntPtr)0;
    }
}
3
votes

Much easier way, in your window constructor just set

this.MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;

and the window will not cover the task bar.

0
votes

Take a look at Microsoft.Windows.Shell. It does all that and more for you. Tracking it down is a little frustrating. I think the best one to use is that included with the latest ribbon control.