如何在WinForms中获得类似StackPanel的布局

时间:2011-03-14 14:09:15

标签: .net winforms

我创建了一个包含三个按钮的对话框。 我将这些按钮放在FlowLayoutPanel中,并将FlowDirection设置为TopDown。

我尝试将按钮调整到面板的宽度,然后将Anchor设置为Left + Top + Right。这似乎对FlowLayoutPanel无效。

有一个简单的解决方案吗?我知道我可以使用FlowLayoutPanel的OnResize事件,并朝着那个方向前进,但希望能够进行设计时设置。

4 个答案:

答案 0 :(得分:22)

如果显式行管理不太烦人,您可以使用TableLayoutPanel

答案 1 :(得分:12)

要实现此布局,只需在FlowLayoutPanel上设置以下所有属性:

AutoScroll = True
FlowDirection = TopDown
WrapContents = False

查看this了解详情

答案 2 :(得分:5)

FlowLayoutPanel可能是最合适的控件。它避免了TableLayoutPanel的行管理方面。

答案 3 :(得分:0)

晚了将近十年,抱歉,但我想我会分享我刚刚编写的扩展程序,以在非流方向自动调整 FlowLayoutPanel 的子项的大小。例如,如果面板的 FlowDirection 是 TopDown,则不能将子项锚定到 Left 和 Right(它将子项缩小为零宽度),但是如果在 InitializeComponent() 之后在面板上调用此扩展,您将得到与您能够做到的效果相同。

它还可以指定一个孩子来填充流动方向上的剩余空间。

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