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();
}
}