26

I created a dialog with three buttons. I put those buttons in a FlowLayoutPanel with FlowDirection set to TopDown.

I attempted to Size the buttons to the width of the panel and then set the Anchor to Left+Top+Right. This seems to have no effect in a FlowLayoutPanel.

Is there a simple solution to this? I know I can use the FlowLayoutPanel's OnResize event, and go that direction, but was hoping for a design-time setting.

hometoast
  • 11,522
  • 5
  • 41
  • 58
  • 3
    [FlowLayoutPanel](https://msdn.microsoft.com/en-us/library/system.windows.forms.flowlayoutpanel%28v=vs.110%29.aspx) is closest to WPF's StackPanel. [TableLayoutPanel](https://msdn.microsoft.com/en-us/library/system.windows.forms.tablelayoutpanel%28v=vs.110%29.aspx) is more like WPF's Grid. – Colonel Panic Feb 06 '15 at 14:46

4 Answers4

24

To achieve this layout, merely set all the following properties on a FlowLayoutPanel:

AutoScroll = True
FlowDirection = TopDown
WrapContents = False

Check this for details

Yen NQ
  • 749
  • 7
  • 12
  • 2
    No. The point of the question is to have buttons or labels in the container stack top to bottom AND resize with the container as they would if you Anchored Left+Top+Right. – hometoast Feb 12 '15 at 12:18
  • 3
    I know this is an old question, but I came here looking for exactly what @hometoast just said. The FlowLayoutPanel doesn't let the child control anchor L+T+R. – DaleyKD Apr 09 '15 at 13:33
  • It did the trick for me (WrapContents was the very last of the options and I totally missed it :-) ) – Xan-Kun Clark-Davis Jan 21 '18 at 05:54
  • 1
    For me it worked but with WrapContents = True so the contents are wrapped and moved accordingly when resized – Stefan Pintilie Mar 08 '22 at 17:59
23

You can use the TableLayoutPanel, if the explicit row management isn't too annoying.

xod
  • 589
  • 3
  • 5
  • Ha! I knew it was something super simple -- just couldn't see it. – hometoast Mar 14 '11 at 14:21
  • 1
    `TableLayoutPanel` is veeeery slow control. It's not good idea if you have a lot of controls in stack, especially `TableLayoutPanel` nested inside `TableLayoutPanel` – 23W Sep 19 '19 at 14:29
6

A FlowLayoutPanel is probably the most appropriate control. It avoids the row management aspect of TableLayoutPanel.

dahvyd
  • 481
  • 2
  • 7
  • 11
  • 3
    But it won't layout the controls like I wanted at design time. (can't believe I remember this even tho the question is 4.5 years old!) – hometoast Aug 27 '14 at 11:04
0

Almost a decade late, sorry, but I thought I'd share the extension I just wrote to automatically resize children of a FlowLayoutPanel in the non-flow direction. For example, if the panel's FlowDirection is TopDown, you can't anchor children to Left and Right (it shrinks the child to zero width), but if you call this extension on the panel after InitializeComponent(), you'll get the same effect as if you were able to.

It also has the capability to designate one child to fill in the remaining space in the flow direction as well.

/// <summary>
/// Sets up children of a FlowLayoutPanel to auto-resize with the panel in the non-flow dimension.
/// (This is a workaround for the lack of support for anchoring both sides of a child inside FlowLayoutPanel.)
/// Optionally also resizes one control to fill remaining space in the flow dimension.
/// </summary>
/// <param name="fillControl">Optional child control to fill remaining space in the flow direction.</param>
public static void AutoSizeChildren(this FlowLayoutPanel panel, Control fillControl = null) {
    // wrapping does not make sense with auto-resizing
    panel.WrapContents = false;

    var isVertical = panel.FlowDirection.In(FlowDirection.TopDown, FlowDirection.BottomUp);
    int dim(Control c, bool flowDir = false) => isVertical ^ flowDir ? c.Width : c.Height;
    void setDim(Control c, int size, bool flowDir = false) {
        if (isVertical ^ flowDir)
            c.Width = size;
        else
            c.Height = size;
    }
    var children = panel.Controls.Cast<Control>().ToList();
    var relSizes = children.ToDictionary(c => c, c => dim(c) - dim(panel));

    // update relative size when controls are resized
    var isPanelResizing = false;
    foreach (var child in children) {
        child.Resize += (s, e) => {
            if (!isPanelResizing)
                relSizes[child] = dim(child) - dim(panel);
        };
    }

    // resize children when panel is resized
    panel.Resize += (s, e) => {
        isPanelResizing = true;
        foreach (var child in children)
            setDim(child, dim(panel) + relSizes[child]);
        isPanelResizing = false;
    };

    if (fillControl != null) {
        // add the size difference between the panel and its children to the fillControl
        void sizeFill() {
            var childrenSize = children.Sum(c => dim(c, true) + (isVertical ? c.Margin.Vertical : c.Margin.Horizontal));
            var diff = dim(panel, true) - childrenSize - (isVertical ? panel.Padding.Vertical : panel.Padding.Horizontal);
            if (diff != 0)
                setDim(fillControl, dim(fillControl, true) + diff, true);
        }
        panel.Resize += (s, e) => sizeFill();
        foreach (var child in children)
            child.Resize += (s, e) => sizeFill();
    }
}
Matt Miller
  • 443
  • 4
  • 10