Click here to Skip to main content
15,887,585 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Based on some Tutorials on the web, I've created a Winforms Class that is border and Titlebarless, but still got the Aero Peek functions.

The Code works fine as long as you have at least 1 Pixel of the Main Form not covered by any other Control, but I've ran into an issue.

When Maximized the Form gets cutoff on all edges by 9 Pixels... In the Tutorial the Problem was solved by adding a new Padding when the Form is maximized.

I don't like this approach, because it's not solving the real issue.

My current Code is as follows:

C#
<pre>using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Extensions.Controls
{
    /// <summary>
    /// <inheritdoc cref="Form"/>
    /// </summary>
    public class BorderLessForm : Form
    {

        /// <summary>
        /// <inheritdoc cref="FormWindowState"/>
        /// </summary>
        public new FormWindowState WindowState
        {
            get => base.WindowState;

            set
            {
                if (value != base.WindowState)
                {
                    base.WindowState = value;

                    this.WindowStateChanged?.Invoke(this, EventArgs.Empty);
                    this.Refresh();
                }
            }
        }


        #region Events

        /// <summary>
        /// Is raised whenever the Form's <seealso cref="WindowState"/> changed
        /// </summary>
        public event EventHandler WindowStateChanged;


        protected override void OnResize(EventArgs e)
        {
            Rectangle maxBounds = Screen.GetWorkingArea(this);
            maxBounds.Inflate(-1, -1);

            if (!this.DesignMode)
            {
                if ((this.Width < maxBounds.Width || this.Height < maxBounds.Height) && this.WindowState != FormWindowState.Minimized)
                {
                    this.WindowState = FormWindowState.Normal;

                    this.WindowStateChanged?.Invoke(this, e);
                }

                if (this.Width >= maxBounds.Width && this.Height >= maxBounds.Height)
                {
                    this.WindowState = FormWindowState.Maximized;

                    this.WindowStateChanged?.Invoke(this, e);
                }

                if (this.WindowState == FormWindowState.Maximized)
                    this.Padding = new Padding(9);
                else
                    this.Padding = new Padding(1);
            }

            base.OnResize(e);
        }


        protected override void OnLocationChanged(EventArgs e)
        {
            Rectangle maxBounds = Screen.GetWorkingArea(this);
            maxBounds.Inflate(-1, -1);

            //if (maxBounds != Rectangle.Empty)
            //this.MaximizedBounds = maxBounds;

            base.OnLocationChanged(e);
        }




        [DllImport("user32.DLL", EntryPoint = "ReleaseCapture")]
        private extern static void ReleaseCapture();

        [DllImport("user32.DLL", EntryPoint = "SendMessage")]
        private extern static void SendMessage(System.IntPtr hWnd, int wMsg, int wParam, int lParam);

        protected override void WndProc(ref Message m)
        {
            const int WM_NCCALCSIZE = 131;//Standar Title Bar - Snap Window
            const int WM_NCHITTEST = 132;//Win32, Mouse Input Notification: Determine what part of the window corresponds to a point, allows to resize the form.
            const int resizeAreaSize = 10;

            //Remove border and keep snap window
            if (m.Msg == WM_NCCALCSIZE && m.WParam.ToInt32() == 1)
            {
                return;
            }

            if (this.DesignMode)
            {
                base.WndProc(ref m);

                return;
            }
            

            #region Form Resize

            // Resize/WM_NCHITTEST values
            const int HTCLIENT = 1; //Represents the client area of the window
            const int HTLEFT = 10;  //Left border of a window, allows resize horizontally to the left
            const int HTRIGHT = 11; //Right border of a window, allows resize horizontally to the right
            const int HTTOP = 12;   //Upper-horizontal border of a window, allows resize vertically up
            const int HTTOPLEFT = 13;//Upper-left corner of a window border, allows resize diagonally to the left
            const int HTTOPRIGHT = 14;//Upper-right corner of a window border, allows resize diagonally to the right
            const int HTBOTTOM = 15; //Lower-horizontal border of a window, allows resize vertically down
            const int HTBOTTOMLEFT = 16;//Lower-left corner of a window border, allows resize diagonally to the left
            const int HTBOTTOMRIGHT = 17;//Lower-right corner of a window border, allows resize diagonally to the right
            /////<Doc> More Information: https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-nchittest </Doc>
            if (m.Msg == WM_NCHITTEST)
            { //If the windows m is WM_NCHITTEST
                base.WndProc(ref m);
                if (this.WindowState == FormWindowState.Normal)//Resize the form if it is in normal state
                {
                    if (m.Result == (IntPtr)HTCLIENT)//If the result of the m (mouse pointer) is in the client area of the window
                    {
                        Point screenPoint = new Point(m.LParam.ToInt32()); //Gets screen point coordinates(X and Y coordinate of the pointer)                           
                        Point clientPoint = this.PointToClient(screenPoint); //Computes the location of the screen point into client coordinates                          
                        if (clientPoint.Y <= resizeAreaSize)//If the pointer is at the top of the form (within the resize area- X coordinate)
                        {
                            if (clientPoint.X <= resizeAreaSize) //If the pointer is at the coordinate X=0 or less than the resizing area(X=10) in 
                                m.Result = (IntPtr)HTTOPLEFT; //Resize diagonally to the left
                            else if (clientPoint.X < (this.Size.Width - resizeAreaSize))//If the pointer is at the coordinate X=11 or less than the width of the form(X=Form.Width-resizeArea)
                                m.Result = (IntPtr)HTTOP; //Resize vertically up
                            else //Resize diagonally to the right
                                m.Result = (IntPtr)HTTOPRIGHT;
                        }
                        else if (clientPoint.Y <= (this.Size.Height - resizeAreaSize)) //If the pointer is inside the form at the Y coordinate(discounting the resize area size)
                        {
                            if (clientPoint.X <= resizeAreaSize)//Resize horizontally to the left
                                m.Result = (IntPtr)HTLEFT;
                            else if (clientPoint.X > (this.Width - resizeAreaSize))//Resize horizontally to the right
                                m.Result = (IntPtr)HTRIGHT;
                        }
                        else
                        {
                            if (clientPoint.X <= resizeAreaSize)//Resize diagonally to the left
                                m.Result = (IntPtr)HTBOTTOMLEFT;
                            else if (clientPoint.X < (this.Size.Width - resizeAreaSize)) //Resize vertically down
                                m.Result = (IntPtr)HTBOTTOM;
                            else //Resize diagonally to the right
                                m.Result = (IntPtr)HTBOTTOMRIGHT;
                        }
                    }
                }
                return;
            }

            #endregion 


            base.WndProc(ref m);
        }

        #endregion



        internal void MoveForm()
        {
            ReleaseCapture();
            SendMessage(this.Handle, 0x112, 0xf012, 0);
        }

    }
}


What I have tried:

I tried using MaximizedBounds Property to the current WorkingArea but that results in another bug, where the Form gets out of bounds when Maximized on a secondary Screen.

I've also tried searching for such issue, but haven't found anything usefull... Most likely because FormBorderStyle = None is used more often than overriding the NonClient Area of a Form.
Posted
Updated 19-Jul-22 10:08am
Comments
0x01AA 19-Jul-22 15:37pm    
Why, why the hell one has to hook in something like this? Let windows to it things...
Electro_Attacks 19-Jul-22 16:26pm    
Well, why is Windows dictating the Style for my Window Frame?

If Microsoft would've given us the opportunity to customize our Winforms Style completely no one would need such steps.
Dave Kreskowiak 19-Jul-22 17:42pm    
Because MS best practices aim for a consistent user experience across all application running on Windows.
Electro_Attacks 20-Jul-22 10:44am    
So what would be the best practice when I want a fully dark UI in winforms?
Dave Kreskowiak 20-Jul-22 10:48am    
If I was writing an app that required a highly customized UI, I would have started with WPF, not WinForms.

Try this:
C#
private void Form1_Load(object sender, EventArgs e)
{
    this.WindowState = FormWindowState.Maximized;
    Size me = this.Size;
    me.Width -= 1;
    me.Height -= 1;
    this.WindowState = FormWindowState.Normal;
    this.Location = new Point(0, 0);
    this.Size = me;
}
 
Share this answer
 
Comments
Electro_Attacks 19-Jul-22 16:27pm    
Well, this would only help for the primary screen and could cause some flickering...
Richard MacCutchan 19-Jul-22 16:33pm    
Did you actually try it?
Electro_Attacks 19-Jul-22 16:39pm    
Well, the flickering Part is a suggestion, but the other Part is obvious, because the Load Event's only get called once...
Richard MacCutchan 20-Jul-22 2:52am    
Did you consider using the code somewhere other than in the FormLoad method?
Quote:
When Maximized the Form gets cutoff on all edges by 9 Pixels...

This isn't true, the form is overlapping the screen area by 9 pixels.
I'm currently on the very same problem, where my not perfect solution is to set this.MaximizedBounds like this:
C#
private void frmMain_LocationChanged(object sender, EventArgs e)
{
    // Screens may be different in size, therefore request the size on form movement
    Rectangle b = Screen.FromHandle(this.Handle).WorkingArea;
    this.MaximizedBounds = new Rectangle(0, 0, (b.Width - 1), b.Height);
}
Not perfect because there is a 1 pixel stripe to the right of the maximized form, but setting it to
C#
private void frmMain_LocationChanged(object sender, EventArgs e)
{
    // Screens may be different in size, therefore request the size on form movement
    Rectangle b = Screen.FromHandle(this.Handle).WorkingArea;
    this.MaximizedBounds = new Rectangle(0, 0, b.Width, b.Height);
}
(suggested to not overlap the taskbar) the original problem is there again.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900