Search code examples
c#winformsresizewindow-resize

Resize form by only specific sizes


I want to allow any form height, but only specific widths (300, 550 , 800, ...(+250)). I tried this code:

Resize += (s, a) => {
    if (Width < 425)
        Width = 300;
    else if (Width < 675)
        Width = 550;
    else if (Width < 925)
        Width = 800;
    else ... 
};

When I try to resize my form, border fluctuates between mouse position and expected width. How can I achieve that behaviour?


Solution

  • Sizing or BeforeResize event for Form

    To control size of the form, ResizeEnd or SizeChanged are a bit late and if you want to change the size in those events, it results in flickering.

    To handle sizing before the new size applies, you can hanlde WM-SIZING message which includes the proposed size and the edge of the form which has triggered the resize.

    In the following example, I've set a tile size for the form and tried to resize based on the tiles:

    enter image description here

    private int widthGridSize = 200;
    private int heightGridSize = 1;
    
    private const int WM_SIZING = 0x0214;
    enum EdgeType : int
    {
        WMSZ_LEFT = 1,
        WMSZ_RIGHT = 2,
        WMSZ_TOP = 3,
        WMSZ_TOPLEFT = 4,
        WMSZ_TOPRIGHT = 5,
        WMSZ_BOTTOM = 6,
        WMSZ_BOTTOMLEFT = 7,
        WMSZ_BOTTOMRIGHT = 8
    }
    [StructLayout(LayoutKind.Sequential)]
    public class RECT
    {
        public int L, T, R, B;
        public int W => R - L;
        public int H => B - T;
    }
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_SIZING)
        {
            var flag = (EdgeType)m.WParam;
            var rect = new RECT();
            Marshal.PtrToStructure(m.LParam, rect);
            var w = (int)Math.Round((double)rect.W / widthGridSize) * widthGridSize;
            var h = (int)Math.Round((double)rect.H / heightGridSize) * heightGridSize;
            switch (flag)
            {
                case EdgeType.WMSZ_LEFT:
                    rect.L = rect.R - w;
                    break;
                case EdgeType.WMSZ_RIGHT:
                    rect.R = rect.L + w;
                    break;
                case EdgeType.WMSZ_TOP:
                    rect.T = rect.B - h;
                    break;
                case EdgeType.WMSZ_TOPLEFT:
                    rect.T = rect.B - h;
                    rect.L = rect.R - w;
                    break;
                case EdgeType.WMSZ_TOPRIGHT:
                    rect.T = rect.B - h;
                    rect.R = rect.L + w;
                    break;
                case EdgeType.WMSZ_BOTTOM:
                    rect.B = rect.T + h;
                    break;
                case EdgeType.WMSZ_BOTTOMLEFT:
                    rect.B = rect.T + h;
                    rect.L = rect.R - w;
                    break;
                case EdgeType.WMSZ_BOTTOMRIGHT:
                    rect.B = rect.T + h;
                    break;
                default:
                    break;
            }
            Marshal.StructureToPtr(rect, m.LParam, true);
            m.Result = (IntPtr)1;
        }
        else
            base.WndProc(ref m);
    }