49

is it possible to make the inserted items in FlowLayoutPanel automatic size of the FlowLayoutPanel? Here is an example:

A form with 1 FlowLayoutPanel and 3 buttons inside:

enter image description here

if I resize the form, the controls look like this: they arrange "left to right"

enter image description here

What I want is this: The controls should have the width of the FlowLayoutPanel:

enter image description here

Any Ideas how to do this? I changed the FlowDirection and played with the Anchor property but with no luck.

I could of course Resize the controls in the FlowLayoutPanel_Resize event, but I want to add about 500 usercontrols - I tested it and it is slow.

MilMike
  • 12,571
  • 15
  • 65
  • 82
  • 4
    Yes, Resize works fine. What ever you do, do *not* add 500 controls, it will suck serious mud. A form shouldn't have more than 50 controls. – Hans Passant Mar 22 '11 at 18:09
  • I am trying to create some kind of a "ListView" like the one in Apple Automator: http://bit.ly/fxkMaH – MilMike Mar 22 '11 at 18:13
  • I only see 4 items in the link you provided, not 500. – Justin Mar 22 '11 at 20:01
  • 1
    @Justin the screenshots are simplified. – MilMike Mar 22 '11 at 20:19
  • I just wanted to point out that for me, resize works ok. I also use double-buffering all over the place so maybe that makes it feel faster (because it doesn't flicker). But certainly I'm not adding 500 controls... I can't imagine how unusable that would be, poor user. – Camilo Martin Feb 14 '13 at 10:59

7 Answers7

51

I suggest you using TableLayoutPanel with one column in this case. I have found TableLayoutPanel much more predictable and solid than FlowLayoutPanel.

Another option, if you still want to use FlowLayoutPanel, is to set first control width to desired one, and use Dock = Top for all other controls.

arbiter
  • 9,447
  • 1
  • 32
  • 43
  • 3
    But then each time you add a control in it you have to manage the number of rows of the table, right? – J4N Oct 10 '17 at 12:54
  • Not necessary. When you add a control just set Dock=Top and its behavior will follow that of the first one in the list. You just have to make sure that when the size of the FlowLayoutPanel is changed you set flayoutpanel.Controls[0].Width=flayoutpanel.Width. – tedebus Jul 02 '21 at 14:13
  • So the width of items in the flow layout is determined by the first item. Got it. – Cillié Malan Dec 07 '22 at 12:36
20

It's simple way to do this. Just bind the SizeChanged evnent of you flowLayoutPannel and resize the containing control. Like:

private void myFlowLayoutPannel_SizeChanged(object sender, EventArgs e)
{
    myFlowLayoutPannel.SuspendLayout();
    foreach (Control ctrl in pnSMS.Controls)
    {
        if (ctrl is Button) ctrl.Width = pnSMS.ClientSize.Width;
    }
    myFlowLayoutPannel.ResumeLayout();
}
SuperLucky
  • 595
  • 5
  • 15
  • This was my first thought too when encountering this issue, but couldn't this slow down the GUI? – ASA May 20 '14 at 13:40
  • Super man, it is working fine for me. I mixes above solution with this one :) – Amir Apr 10 '15 at 08:24
  • 4
    Too old, but I would suggest using the `Layout` event of `FlowLayoutPannel` to resize the controls. – bansi Sep 12 '17 at 03:59
12

here I have my StackPanel class:

/// <summary>
/// A stackpanel similar to the Wpf stackpanel.
/// </summary>
public class StackPanel: FlowLayoutPanel
{
    public StackPanel(): base()
    {
        InitializeComponent();
        this.ForceAutoresizeOfControls = true;
    }

    private void InitializeComponent()
    {
        this.SuspendLayout();
        //
        // StackPanel
        //
        this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
        this.WrapContents = false;
        this.ResumeLayout(false);
    }

    /// <summary>
    /// Override it just in order to hide it in design mode.
    /// </summary>
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public new bool WrapContents
    {
        get { return base.WrapContents; }
        set { base.WrapContents = value; }
    }

    /// <summary>
    /// Override it just in order to set its default value.
    /// </summary>
    [DefaultValue(typeof(AutoSizeMode), "GrowAndShrink")]
    public override AutoSizeMode AutoSizeMode
    {
        get { return base.AutoSizeMode; }
        set { base.AutoSizeMode = value; }
    }

    /// <summary>
    /// Get or set a value that when is true forces the resizing of each control.
    /// If this value is false then only control that have AutoSize == true will be resized to
    /// fit the client size of this container.
    /// </summary>
    [DefaultValue(true)]
    public bool ForceAutoresizeOfControls { get; set; }

    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        this.SuspendLayout();
        switch (FlowDirection)
        {
            case FlowDirection.BottomUp:
            case FlowDirection.TopDown:
                foreach (Control control in this.Controls)
                    if (ForceAutoresizeOfControls || control.AutoSize)
                        control.Width = this.ClientSize.Width - control.Margin.Left - control.Margin.Right;
                break;
            case FlowDirection.LeftToRight:
            case FlowDirection.RightToLeft:
                foreach (Control control in this.Controls)
                    if (ForceAutoresizeOfControls || control.AutoSize)
                        control.Height = this.ClientSize.Height - control.Margin.Top - control.Margin.Bottom;
                break;
            default:
                break;
        }
        this.ResumeLayout();
    }

    protected override void OnLayout(LayoutEventArgs levent)
    {
        base.OnLayout(levent);

        if (levent != null && levent.AffectedControl != null)
        {
            Control control = levent.AffectedControl;
            if (ForceAutoresizeOfControls || control.AutoSize)
            {
                switch (FlowDirection)
                {
                    case FlowDirection.BottomUp:
                    case FlowDirection.TopDown:
                        control.Width = this.ClientSize.Width - control.Margin.Left - control.Margin.Right;
                        break;
                    case FlowDirection.LeftToRight:
                    case FlowDirection.RightToLeft:
                        control.Height = this.ClientSize.Height - control.Margin.Top - control.Margin.Bottom;
                        break;
                    default:
                        break;
                }
            }
        }
    }
}
Teolazza
  • 325
  • 3
  • 7
5

There is no need for a FlowLayoutPanel here.

You should be able to do what you want with a normal Panel control. Anchor it at all four sides so that it stretches with your form, then add your buttons and set them all to Dock: Top.

EDIT - In response to @UsamaAziz comment.

To ensure the controls which are hidden beyond the bottom of the panel are accessible, set the "AutoScroll" property of the panel to True. This will add a vertical scrollbar to the panel when it is required.

Job Done.

Gravitate
  • 2,885
  • 2
  • 21
  • 37
  • And if I want to add 100 controls in it? I don't think panel can handle that because it doesn't has a scrollbar. – Usama Aziz Dec 19 '20 at 07:37
  • 1
    @UsamaAziz It can. Just set the panel's "AutoScroll" property to True. Then when the controls extend beyond the bottom of the panel, a vertical scrollbar will be automatically added. – Gravitate Aug 10 '21 at 16:22
3

The FlowLayoutPanel arranges controls in a particular way, according to MSDN:

...for vertical flow directions, the FlowLayoutPanel control calculates the width of an implied column from the widest child control in the column. All other controls in this column with Anchor or Dock properties are aligned or stretched to fit this implied column. The behavior works in a similar way for horizontal flow directions.

Its not ideal, but you can do this natively, as long as one child control is set to the same width as the container, and the rest of the controls are set to Dock.

CrazyTim
  • 6,695
  • 6
  • 34
  • 55
2

I Suggest... try playing with the anchors of the buttons... try setting it as

Button1.Anchor = (AnchoreStyle.Left or AnchoreStyle.Right)

or set it in the properties...

and then put it inside a Panel instead of the FlowLayoutPanel... ;)

EdChum
  • 376,765
  • 198
  • 813
  • 562
clakids
  • 21
  • 1
1

As other answers stated, the Panel itself is sufficient to handle your buttons. Bit of code that works for me:

public class ButtonWindow : Panel
{
    public ButtonWindow()
    {
        Dock = DockStyle.Fill;
        AutoScroll = true;

        for (int i = 0; i < 500; i++) 
        {
           Button button = new Button() { Height = 100, Dock = DockStyle.Top };
           Controls.Add(button);
        }
    }
}

Have a nice day.