36

I have a situation where it would be beneficial to me to allow my windows form to be resized by the user, but only vertically. After some searching, it seems like there isn't much on this particular subject. Is it possible?

Bo Persson
  • 86,087
  • 31
  • 138
  • 198
Ben
  • 7,182
  • 13
  • 43
  • 62
  • 10
    @Will: That depends what the form is displaying. There are (some) cases where this is a good idea. – SLaks Jan 26 '10 at 16:50
  • 7
    @slaks never seen it. Seen plenty of apps that think they know how big a form should be. Visual Studio still has a few of them. These forms have one thing in common--the people who made them were wrong about the "right" size. In all cases, let the user decide what the size of the form is, or risk damnation. (Full disclosure, I risk damnation. I am ashamed.) –  Jan 26 '10 at 16:54
  • 4
    @Will: How about Virtual PC 2007? – SLaks Jan 26 '10 at 16:55
  • 1
    @dada686 On Vista, Freecell can be resized and scales, which is great. I came here because I have a 3-line window: two text fields and a button. So resizing it vertically makes no sense, right...? Well, I'm not so sure any more. For vertical resizing, I could make the text fields taller and the font larger! It's an unusual feature, but it doesn't hurt. – Evgeni Sergeev Aug 09 '13 at 08:52

6 Answers6

77

You need to set the form's MinimumSize and MaximumSize properties to two sizes with different heights but equal widths.

If you don't want the horizontal resize cursor to appear at all, you'll need to handle the WM_NCHITTEST message, like this:

protected override void WndProc(ref Message m) {
    base.WndProc(ref m);
    switch (m.Msg) {
        case 0x84: //WM_NCHITTEST
            var result = (HitTest)m.Result.ToInt32();
            if (result == HitTest.Left || result == HitTest.Right)
                m.Result = new IntPtr((int)HitTest.Caption);
            if (result == HitTest.TopLeft || result == HitTest.TopRight)
                m.Result = new IntPtr((int)HitTest.Top);
            if (result == HitTest.BottomLeft || result == HitTest.BottomRight)
                m.Result = new IntPtr((int)HitTest.Bottom);

            break;
    }
}
enum HitTest {
    Caption = 2,
    Transparent = -1,
    Nowhere = 0,
    Client = 1,
    Left = 10,
    Right = 11,
    Top = 12,
    TopLeft = 13,
    TopRight = 14,
    Bottom = 15,
    BottomLeft = 16,
    BottomRight = 17,
    Border = 18
}
SLaks
  • 800,742
  • 167
  • 1,811
  • 1,896
  • 5
    Can't believe I didn't think of this... Very nice! And thanks for the WndProc particulars of hiding that resize cursor! – Ben Jan 26 '10 at 16:51
  • Just a comment... shouldn't you make the HitTest.Left and .Right return None and not Caption? Using Caption makes the window draggable at those locations, no? – Mark A. Donohoe Mar 22 '16 at 15:25
  • @MarqueIV: Yes; I consider that a feature. – SLaks Mar 22 '16 at 15:35
  • I agree it's a nice feature to have--to be able to drag the window around from someplace other than the caption, but if you're going that route, I'd do it for anywhere where NCHitTest would normally return None so you can drag it from other parts of the client area too. Without allowing that, there isn't any distinction or feedback to the user that the edges have a different behavior whereas if it always moved regardless, it would. Of course playing my own adversary, I could also say allowing moving from anywhere other than the caption is also a non-consistent interface so there's that too. – Mark A. Donohoe Mar 22 '16 at 15:45
13

Just an idea...

public partial class Form1 : Form {
    int _width;

    public Form1() {
        _width = this.Width;
        InitializeComponent();
    }

    protected override void OnResize(EventArgs e) {
        this.Width = _width;
        base.OnResize(e);
    }
}

EDIT: please note that the min/max size solutions work much better than this hack :)

Paolo Tedesco
  • 49,782
  • 29
  • 130
  • 181
  • Beat me to it. +1 For other solutions, I'm not sure that it's possible to actually have a max/min width without also setting a max/min height. This solution will allow you to resize the form, but it will rubber-band back to it's original width. – George Johnston Jan 26 '10 at 16:44
  • @George: You can just set a small minimum and a very large maximum. – SLaks Jan 26 '10 at 16:49
7

Set the max & min size for the width of the form only.

Gabe
  • 46,932
  • 26
  • 137
  • 178
  • 1
    Be sure to do so in the Load event, not the constructor. Or automatic scaling will clip the form content. – Hans Passant Jan 26 '10 at 16:52
  • 1
    If you leave the height component of the MinimumSize and MaximumSize properties at 0 but set a width, it will constrain the window to its minimum height. MinimumSize and MaximumSize constraints are only ignored when both components are zero - if one's set and the other is left at zero, it will enforce both components literally. – Dathan Jan 26 '10 at 16:56
  • Do it in the properties pane at Design Time. There's no need to use any code to make the form only scroll vertically. –  Mar 29 '11 at 04:16
3

Let the FormBorderStyle to Resizable and set MaximumSize and MinimumSize = new Size(this.Width, 0)

Correction:

this.MinimumSize = new Size(this.Width, 0);
this.MaximumSize = new Size(this.Width, Int32.MaxValue);
Alex LE
  • 17,974
  • 4
  • 28
  • 28
  • 2
    MinimumSize and MaximumSize components are only interpreted as "no limit" when BOTH components are zero. – Dathan Jan 26 '10 at 16:51
  • @SLaks, You're right! the height need to be set to different value in min and max sizes. – Alex LE Jan 26 '10 at 16:54
1

Yes, it is possible. Just set your form.MinimumSize.Width = form.MaximumSize.Width = 100 (or whatever width you want).

Igor Korkhov
  • 7,489
  • 1
  • 23
  • 30
  • You cannot assign the Width directly as form.MinimunSize or form.MaximumSize returns a value type, not a reference. – Alex LE Jan 26 '10 at 16:56
  • 1
    It was not a working code sample, just an idea of what should be set up. – Igor Korkhov Jan 26 '10 at 17:19
  • I fail to understand how people forget to use logic when trying to understand a simple statement. +1 –  Mar 29 '11 at 04:19
0

To avoid the "rubber-banding" effect of @orsogufo's solution:

public Form1()
{
    InitializeComponent();
    this.MinimumSize = new Size(500, 0);
    this.MaximumSize = new Size(500, Screen.AllScreens.Max(s => s.Bounds.Height));
}

It won't correctly adjust its maximum height to accommodate a larger screen if you resize the screen bounds, but for static screen sizes it works great.

Dathan
  • 6,982
  • 2
  • 23
  • 45