Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Custom Border (Windows 10 Style)

0.00/5 (No votes)
28 Feb 2016 2  
I made this borderless application (WinForms), and added an semitransperent border (might laggy). The design is exactly the Windows 10 colors and button sizes.

Introduction

I´ve made this application because there are many people on the internet who try to make a "custom border". I solved this problem: semi transparent border, laggy resizer, not exactly the right colors, buttons with the right size and more. The bad things are that areosnap don´t work and it overlay parts of the taskbar.

Using the Code

One problem was that if you drag the border while it's maximized, it's restored to normal. But the titlebar doesn´t resize. Because it only detects if you press the MaximizeRestoreButton. So I must detect when the Windowstate changes, but there wasn´t any eventhandler for this. I solved it with this code.

Here, we make a variable for the last WindowState:

private FormWindowStatem LastState;

Now, we override the OnClientSizeChanged, and detect if the windowstate has changed.

protected override void OnClientSizeChanged(EventArgs e)
        {
            if (this.WindowState != mLastState)
            {
                mLastState = this.WindowState;
                OnWindowStateChanged(e);
            }
            base.OnClientSizeChanged(e);
        }

If the windowstate has changed, we come to this void:

protected void OnWindowStateChanged(EventArgs e)
        {
            if (WindowState == FormWindowState.Maximized)
            {
                TitleBarButtonMaximizeRestore.Image = Properties.Resources.ButtonFontRestore;

                TitleBarContainer.Size = new Size(TitleBarContainer.Size.Width +6, 25);
                TitleBarContainer.Location = new Point
                (TitleBarContainer.Location.X -3, TitleBarContainer.Location.Y -3);

                MainContainer.Size = new Size
                (MainContainer.Size.Width + 6, MainContainer.Size.Height + 5 + 6);
                MainContainer.Location = new Point
                (MainContainer.Location.X - 3, MainContainer.Location.Y - 5 -3);
            }
            else if (WindowState == FormWindowState.Normal)
            {
                TitleBarButtonMaximizeRestore.Image = Properties.Resources.ButtonFontMaximize;

                TitleBarContainer.Size = new Size(TitleBarContainer.Size.Width -6, 30);
                TitleBarContainer.Location = new Point
                (TitleBarContainer.Location.X +3, TitleBarContainer.Location.Y +3);

                MainContainer.Size = new Size
                (MainContainer.Size.Width - 6, MainContainer.Size.Height - 5 - 6);
                MainContainer.Location = new Point
                (MainContainer.Location.X +3, MainContainer.Location.Y + 5 +3);
            }
        }

Here, I check the new windowstate and if the form is maximized, we remove the border, and change the image of the TitleBarButtonMaximizeRestore to restore. If the new windowstate is normal, we bring back the border and set the image of TitleBarButtonMaximizeRestore to the maximize image.

So, here is the hardest part: make the borderless form resizable: We overwrite the "WndProc".

protected override void WndProc(ref Message m)
        {
            const uint WM_NCHITTEST = 0x0084;
            const uint WM_MOUSEMOVE = 0x0200;

            const uint HTLEFT = 10;
            const uint HTRIGHT = 11;
            const uint HTBOTTOMRIGHT = 17;
            const uint HTBOTTOM = 15;
            const uint HTBOTTOMLEFT = 16;
            const uint HTTOP = 12;
            const uint HTTOPLEFT = 13;
            const uint HTTOPRIGHT = 14;

            const int RESIZE_HANDLE_SIZE = 10;
            bool handled = false;
            if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE)
            {
                Size formSize = this.Size;
                Point screenPoint = new Point(m.LParam.ToInt32());
                Point clientPoint = this.PointToClient(screenPoint);

                Dictionary<UInt32, Rectangle> boxes = new Dictionary<UInt32, Rectangle>() {
            {HTBOTTOMLEFT, new Rectangle(0, formSize.Height - 
            RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)},
            {HTBOTTOM, new Rectangle(RESIZE_HANDLE_SIZE, formSize.Height - 
            RESIZE_HANDLE_SIZE, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)},
            {HTBOTTOMRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, 
            formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)},
            {HTRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, 
            RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE)},
            {HTTOPRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, 
            0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) },
            {HTTOP, new Rectangle(RESIZE_HANDLE_SIZE, 0, 
            formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) },
            {HTTOPLEFT, new Rectangle(0, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) },
            {HTLEFT, new Rectangle(0, RESIZE_HANDLE_SIZE, 
            RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE) }
        };

                foreach (KeyValuePair<UInt32, Rectangle> hitBox in boxes)
                {
                    if (hitBox.Value.Contains(clientPoint))
                    {
                        m.Result = (IntPtr)hitBox.Key;
                        handled = true;
                        break;
                    }
                }
            }

            if (!handled)
                base.WndProc(ref m);
        }

Now the simple stuff: make the Form moveable:

private void moveForm_MouseDown(object sender, MouseEventArgs e)
        {
            (sender as Control).Capture = false;
            Message msg = Message.Create
            (Handle, WM_NCLBUTTONDOWN, (IntPtr)HT_CAPTION, IntPtr.Zero);
            WndProc(ref msg);
        }

And make the background semi transparent:

You must set the "TransparencyKey" to any color and set the form backcolor to the same color.

Then, you add an onpaint event to make the full transparent background semitransparent. Just like this:

private void SemiTransperent_Paint(object sender, PaintEventArgs e)
        {
            var hb = new HatchBrush(HatchStyle.Percent50, this.TransparencyKey);
            e.Graphics.FillRectangle(hb, this.DisplayRectangle);
        }

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here