FlowLayoutPanel 显示水平滚动条,内部​​面板的宽度与客户端尺寸宽度相同

FlowLayoutPanel shows horizontal scroll bar with inner panel's width being the same as client size width

我在 FlowLayoutPanel 的 children 在 FlowLayoutPanel 的 ClientSizeChanged 事件中调整大小时遇到​​问题。

我试图让 children 在 FlowLayoutPanel 调整大小时水平调整大小。问题是,即使 child 的边距为 0,FlowLayoutPanel 的填充也为 0,但在执行 ClientSizeChanged 事件处理程序后,FlowLayoutPanel 显示其水平滚动条 而 child 的宽度与 FlowLayoutPanel.ClientSize.Width.

完全相同

我尝试将代码移至 Resize 事件,但我仍然得到相同的结果。

这是一个演示问题的示例,有一个 FlowLayoutPanel 的以下属性已从默认值更改为:

FlowLayoutPanel 中还有一个常规面板:

最后,一个间隔为 1 的计时器,它会更改 FlowLayoutPanel 的宽度并在 FlowLayoutPanel 的 HorizontalScroll.Visibile 属性 为真时禁用自身,并显示一个消息框,通知宽度panel1 和 flow1 的 ClientSize.Width。

代码如下:

    private void timer1_Tick(object sender, EventArgs e)
    {
        flow1.Width -= 1;

        if (flow1.HorizontalScroll.Visible)
        {
            timer1.Enabled = false;
            MessageBox.Show("Panel.Width = " + panel1.Width.ToString() +
                ", FlowPanel.ClientWidth = " + flow1.ClientSize.Width.ToString());
        }
    }

    private void flow1_ClientSizeChanged(object sender, EventArgs e)
    {
        panel1.Width = flow1.ClientSize.Width;
    }

在没有 children 溢出客户端大小的情况下显示水平滚动条背后的逻辑是什么?最重要的是,如何防止它发生?

这是一个事件顺序问题,布局计算得太快了。自动布局有几个讨厌的角落案例,它也可以是双稳态的,布局在两个解决方案之间来回翻转。您可以在您的测试应用程序中看到这一点,在 MessageBox.Show() 调用之前添加 flow1.PerformLayout();,您将看到滚动条再次隐藏。

这就是 SuspendLayout() 方法存在的原因。 Winforms 程序员对它的使用还不够。有充分的理由,很难判断何时需要它。他们真的不想需要它。基本规则是,如果布局必须处理不止一种尺寸变化,则应使用它。

您的测试程序中真正的修复是:

private void timer1_Tick(object sender, EventArgs e) {
    flow1.SuspendLayout();
    flow1.Width -= 1;
    flow1.ResumeLayout(true);
    // etc..
}

你会发现它现在工作得很好,你永远不会看到消息框。