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 的以下属性已从默认值更改为:
- 自动滚动 = 真
- FlowDirection = TopDown
- 保证金 = 0,0,0,0
- 名称 = flow1
- 背景色 = 红色
FlowLayoutPanel 中还有一个常规面板:
- 保证金 = 0,0,0,0
- 名称 = panel1
- 背景颜色:蓝色
最后,一个间隔为 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..
}
你会发现它现在工作得很好,你永远不会看到消息框。
我在 FlowLayoutPanel 的 children 在 FlowLayoutPanel 的 ClientSizeChanged 事件中调整大小时遇到问题。
我试图让 children 在 FlowLayoutPanel 调整大小时水平调整大小。问题是,即使 child 的边距为 0,FlowLayoutPanel 的填充也为 0,但在执行 ClientSizeChanged 事件处理程序后,FlowLayoutPanel 显示其水平滚动条 而 child 的宽度与 FlowLayoutPanel.ClientSize.Width.
完全相同我尝试将代码移至 Resize 事件,但我仍然得到相同的结果。
这是一个演示问题的示例,有一个 FlowLayoutPanel 的以下属性已从默认值更改为:
- 自动滚动 = 真
- FlowDirection = TopDown
- 保证金 = 0,0,0,0
- 名称 = flow1
- 背景色 = 红色
FlowLayoutPanel 中还有一个常规面板:
- 保证金 = 0,0,0,0
- 名称 = panel1
- 背景颜色:蓝色
最后,一个间隔为 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..
}
你会发现它现在工作得很好,你永远不会看到消息框。