40

Does anyone know how I can resize a winform when it has no border. I don't want the default border that Windows has, so I changed the property "FormBorderStyle" to "None". This removed the border, although now it can't be resized. I've figured out how to move the form around, I just need to know how to resize it.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
Joey Morani
  • 25,431
  • 32
  • 84
  • 131

7 Answers7

73

Some sample code that allow moving and resizing the form:

  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
      this.FormBorderStyle = FormBorderStyle.None;
      this.DoubleBuffered = true;
      this.SetStyle(ControlStyles.ResizeRedraw, true);
    }
    private const int cGrip = 16;      // Grip size
    private const int cCaption = 32;   // Caption bar height;

    protected override void OnPaint(PaintEventArgs e) {
      Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
      ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
      rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption);
      e.Graphics.FillRectangle(Brushes.DarkBlue, rc);
    }

    protected override void WndProc(ref Message m) {
      if (m.Msg == 0x84) {  // Trap WM_NCHITTEST
        Point pos = new Point(m.LParam.ToInt32());
        pos = this.PointToClient(pos);
        if (pos.Y < cCaption) {
          m.Result = (IntPtr)2;  // HTCAPTION
          return;
        }
        if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip) {
          m.Result = (IntPtr)17; // HTBOTTOMRIGHT
          return;
        }
      }
      base.WndProc(ref m);
    }
  }
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Like this I get a blue ugly bar at the top. – C4d Aug 14 '15 at 10:50
  • 1
    If you don't want the bar on top just don't override OnPaint(). The rest of the code is solid. Thanks a bunch mate :) – kurt Apr 21 '16 at 22:32
  • 2
    To remove the top border and ONLY have the sizer grip, simply remove the last two lines of the OnPaint method: `rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption); e.Graphics.FillRectangle(Brushes.DarkBlue, rc);` – ryancdotnet Jun 25 '20 at 17:49
  • do I need to include something special? because I cant make it work. looks like `WndProc` gets called but `m.Msg` is never equal to 0x84. .NET Framework 4.8 – LongToeBoy Jul 01 '21 at 15:59
  • 1
    Nevermind. I had panel in my form with `dock: fill` so it was completely covering client area and mouse was always hovering over control and was never at client area thus `WM_NCHITTEST` was never firing... simply undocking worked. – LongToeBoy Jul 01 '21 at 16:25
  • This works but there is a lot of "shaking" of the controls inside the form when pulling left or top. The same happens to the opposite edge of the form itself. It seems the call to WM_NCHITTEST comes after the form has moved (or something) and the code kind of sets it back in place. Not a big deal but nasty looking thing. The DoubleBuffered and ResizeRedraw flags do not fix it. –  Sep 08 '22 at 07:17
32

Here's a complete example of a customized form with all 8 points of resizing:

public partial class Form1 : Form {
public Form1() {
  InitializeComponent();
  this.FormBorderStyle = FormBorderStyle.None; // no borders
  this.DoubleBuffered = true;
  this.SetStyle(ControlStyles.ResizeRedraw, true); // this is to avoid visual artifacts
}

protected override void OnPaint(PaintEventArgs e) // you can safely omit this method if you want
{
    e.Graphics.FillRectangle(Brushes.Green, Top);
    e.Graphics.FillRectangle(Brushes.Green, Left);
    e.Graphics.FillRectangle(Brushes.Green, Right);
    e.Graphics.FillRectangle(Brushes.Green, Bottom);
}

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

const int _ = 10; // you can rename this variable if you like

Rectangle Top { get { return new Rectangle(0, 0, this.ClientSize.Width, _); } }
Rectangle Left { get { return new Rectangle(0, 0, _, this.ClientSize.Height); } }
Rectangle Bottom { get { return new Rectangle(0, this.ClientSize.Height - _, this.ClientSize.Width, _); } }
Rectangle Right { get { return new Rectangle(this.ClientSize.Width - _, 0, _, this.ClientSize.Height); } }

Rectangle TopLeft { get { return new Rectangle(0, 0, _, _); } }
Rectangle TopRight { get { return new Rectangle(this.ClientSize.Width - _, 0, _, _); } }
Rectangle BottomLeft { get { return new Rectangle(0, this.ClientSize.Height - _, _, _); } }
Rectangle BottomRight { get { return new Rectangle(this.ClientSize.Width - _, this.ClientSize.Height - _, _, _); } }


protected override void WndProc(ref Message message)
{
    base.WndProc(ref message);

    if (message.Msg == 0x84) // WM_NCHITTEST
    {
        var cursor = this.PointToClient(Cursor.Position);

        if (TopLeft.Contains(cursor)) message.Result = (IntPtr)HTTOPLEFT;
   else if (TopRight.Contains(cursor)) message.Result = (IntPtr)HTTOPRIGHT;
   else if (BottomLeft.Contains(cursor)) message.Result = (IntPtr)HTBOTTOMLEFT;
   else if (BottomRight.Contains(cursor)) message.Result = (IntPtr)HTBOTTOMRIGHT;

   else if (Top.Contains(cursor)) message.Result = (IntPtr)HTTOP;
   else if (Left.Contains(cursor)) message.Result = (IntPtr)HTLEFT;
   else if (Right.Contains(cursor)) message.Result = (IntPtr)HTRIGHT;
   else if (Bottom.Contains(cursor)) message.Result = (IntPtr)HTBOTTOM;
    }
}}
user1306322
  • 8,561
  • 18
  • 61
  • 122
  • 2
    a little error. edges and corners are overlapping so for example top one that is returning `new Rectangle(0, 0, this.ClientSize.Width, _);` must return `new Rectangle(_, 0, this.ClientSize.Width - _, _);` in order to leave small square for corner square... other edges will also have offsets accordingly – LongToeBoy Jul 01 '21 at 16:57
  • The "error" doesn't make a difference since the corners are checked before the edges – Penguin Jan 25 '22 at 02:26
11

"Sizer" is the light blue panel in the right bottom corner

screenshot of Sizer

    int Mx;
    int My;
    int Sw;
    int Sh;

    bool mov;

    void SizerMouseDown(object sender, MouseEventArgs e)
    {
        mov = true;
        My = MousePosition.Y;
        Mx = MousePosition.X;
        Sw = Width;
        Sh = Height;
    }

    void SizerMouseMove(object sender, MouseEventArgs e)
    {
        if (mov == true) {
            Width = MousePosition.X - Mx + Sw;
            Height = MousePosition.Y - My + Sh;
        }
    }

    void SizerMouseUp(object sender, MouseEventArgs e)
    {
        mov = false;
    }
crusy
  • 1,424
  • 2
  • 25
  • 54
Kuba
  • 111
  • 1
  • 2
  • 1
    A nice solution! However instead of a blue panel I used a small picture box showing an image of the resize dot pattern, with the Cursor property set to "SizeAll" so that the cursor changes to resize arrows when you are over the box. – JonP Jan 15 '20 at 10:55
2

(elaborate : in comment 2)

Resize "Form" From All place And Move it >>> Full Code <<<<<

//First u most to add this Class

 class ReSize
     {

        private bool Above, Right, Under, Left, Right_above, Right_under, Left_under, Left_above;


        int Thickness=6;  //Thickness of border  u can cheang it
        int Area = 8;     //Thickness of Angle border 


        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="thickness">set thickness of form border</param>
        public ReSize(int thickness)
        {
            Thickness = thickness;
        }

        /// <summary>
        /// Constructor set thickness of form border=1
        /// </summary>
        public ReSize()
        {
            Thickness = 10;
        }

        //Get Mouse Position
        public  string getMosuePosition(Point mouse, Form form)
        {
            bool above_underArea = mouse.X > Area && mouse.X < form.ClientRectangle.Width - Area; /* |\AngleArea(Left_Above)\(=======above_underArea========)/AngleArea(Right_Above)/| */ //Area===>(==)
            bool right_left_Area = mouse.Y > Area && mouse.Y < form.ClientRectangle.Height - Area; 

            bool _Above=mouse.Y <= Thickness;  //Mouse in Above All Area
            bool _Right= mouse.X >= form.ClientRectangle.Width - Thickness;
            bool _Under=mouse.Y >= form.ClientRectangle.Height - Thickness;
            bool _Left=mouse.X <= Thickness;

            Above = _Above && (above_underArea); if (Above) return "a";   /*Mouse in Above All Area WithOut Angle Area */
            Right = _Right && (right_left_Area); if (Right) return "r";
            Under = _Under && (above_underArea); if (Under) return "u";
            Left = _Left && (right_left_Area);   if (Left) return "l";


            Right_above =/*Right*/ (_Right && (!right_left_Area)) && /*Above*/ (_Above && (!above_underArea));   if (Right_above) return "ra";     /*if Mouse  Right_above */
            Right_under =/* Right*/((_Right) && (!right_left_Area)) && /*Under*/(_Under && (!above_underArea));  if (Right_under) return "ru";     //if Mouse  Right_under 
            Left_under = /*Left*/((_Left) && (!right_left_Area)) && /*Under*/ (_Under && (!above_underArea));    if (Left_under) return "lu";      //if Mouse  Left_under
            Left_above = /*Left*/((_Left) && (!right_left_Area)) && /*Above*/(_Above && (!above_underArea));     if (Left_above) return "la";      //if Mouse  Left_above

            return "";

        }


    }

Then Form cs

 public partial class FormGDI : Form
    {

        ReSize resize = new ReSize();     // ReSize Class "/\" To Help Resize Form <None Style>


        public FormGDI()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.ResizeRedraw, true);

        }


        private const int cGrip = 16;      // Grip size
        private const int cCaption = 32;   // Caption bar height;

        protected override void OnPaint(PaintEventArgs e)
        {
            //this if you want to draw   (if)

            Color theColor = Color.FromArgb(10, 20, 20, 20);
            theColor = Color.DarkBlue;
            int BORDER_SIZE = 4;
            ControlPaint.DrawBorder(e.Graphics, ClientRectangle,
                                         theColor, BORDER_SIZE, ButtonBorderStyle.Dashed,
                                         theColor, BORDER_SIZE, ButtonBorderStyle.Dashed,
                                         theColor, BORDER_SIZE, ButtonBorderStyle.Dashed,
                                         theColor, BORDER_SIZE, ButtonBorderStyle.Dashed);


            Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
            ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
            rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption);
            e.Graphics.FillRectangle(Brushes.DarkBlue, rc);



            base.OnPaint(e);
        }


        //set MinimumSize to Form
        public override Size MinimumSize
        {
            get
            {
                return base.MinimumSize;
            }
            set
            {
                base.MinimumSize = new Size(179, 51); 
            }
        }

        //
        //override  WndProc  
        //
        protected override void WndProc(ref Message m)
        {
            //****************************************************************************

            int x = (int)(m.LParam.ToInt64() & 0xFFFF);               //get x mouse position
            int y = (int)((m.LParam.ToInt64() & 0xFFFF0000) >> 16);   //get y mouse position  you can gave (x,y) it from "MouseEventArgs" too
            Point pt = PointToClient(new Point(x, y));

            if (m.Msg == 0x84)
            {
                switch (resize.getMosuePosition(pt, this))
                {
                    case "l": m.Result = (IntPtr)10; return;  // the Mouse on Left Form
                    case "r": m.Result = (IntPtr)11; return;  // the Mouse on Right Form
                    case "a": m.Result = (IntPtr)12; return;
                    case "la": m.Result = (IntPtr)13; return;
                    case "ra": m.Result = (IntPtr)14; return;
                    case "u": m.Result = (IntPtr)15; return;
                    case "lu": m.Result = (IntPtr)16; return;
                    case "ru": m.Result = (IntPtr)17; return; // the Mouse on Right_Under Form
                    case "": m.Result = pt.Y < 32 /*mouse on title Bar*/ ? (IntPtr)2 : (IntPtr)1; return;  

                }
            }

              base.WndProc(ref m);

        }

    }
  • Can you elaborate on how this answers the question? Thanks! – DanM7 Sep 21 '14 at 23:10
  • elaborate : first id make resize class it's have one method this method to determine position of mouse form calculate (`point mouse`) and (`Form form`)to get width and height of form then and the most importanst `WndProc` Override Method this method have `ref Message m` param when `m.msg=0x84`value u can set m.result=10 that mean you call `form` to resize from left and `m.Result=11` call `form` from Right and ....to 17 but when `m.Result=2 you call to move the `form` and when `m.Result=1`that mean call `don't do any thing` – NourAldienArabian Sep 25 '14 at 09:41
  • 1
    it helps, but it doens't handle scrolling, it creates new border 'lines' through the form when scrolling – CularBytes Dec 10 '14 at 22:18
1

The simplest way is to assign mouse events to the form or the title bar, whatever you want to be hold for moving. You can move a BorderLess Form with assigning these methods to there events as names in method.

    int movX,movY;
    bool isMoving;

    private void onMouseDown(object sender, MouseEventArgs e)  
    {
         // Assign this method to mouse_Down event of Form or Panel,whatever you want
        isMoving = true;
        movX = e.X;
        movY = e.Y;
    }

    private void onMouseMove(object sender, MouseEventArgs e)
    {
         // Assign this method to Mouse_Move event of that Form or Panel
        if (isMoving)
        {
            this.SetDesktopLocation(MousePosition.X - movX, MousePosition.Y - movY);
        }
    }

    private void onMouseUp(object sender, MouseEventArgs e)
    {
       // Assign this method to Mouse_Up event of Form or Panel.
        isMoving = false;
    }
Sayed Muhammad Idrees
  • 1,245
  • 15
  • 25
0

If you don't mind a short bar at the top, you can use a "regular" sizable form with the .ControlBox set to false and .Text (the caption bar at the top) set to an empty string.

You'll end up with a resizable form that looks like the Task Manager when you double-click on a chart. The advantage of this method is that when you resize it from the left, the right border does not jerk. The same is also when you resize it from the top.

this.FormBorderStyle = FormBorderStyle.Sizable;
this.ControlBox = false;
this.Text = "";
GDavoli
  • 517
  • 4
  • 8
-2

(1) FormBorderStyle= Sizable or SizableToolWindows enter image description here

(2) clear text in form text

enter image description here

Pradeep Kumar
  • 1,193
  • 1
  • 9
  • 21