1

我正在为包含 UserControls 的 FlowLayoutPanel 使用非自动VScrollBar 控件。

我需要找出 FlowLayoutPanel 中的任何控件是否位于其客户区域之外。我想使用此信息来确定 VScrollBar 是否可见。我在 FlowLayoutPanel 的 Layout 事件处理程序方法中添加了以下代码:

bool lookingForControl = true;
bool controlBelowClientArea = false;
int controlIndex = 0;
int controlBottomPos;
Control[] controlsTemp = new Control[leftFlowLayoutPanel.Controls.Count];
leftFlowLayoutPanel.Controls.CopyTo(controlsTemp, 0);
while (lookingForControl) {
    controlBottomPos = controlsTemp[controlIndex].Bottom +
        controlsTemp[controlIndex].Margin.Bottom;

    debugTextBox.AppendText("Bottom position of control " + controlIndex + 
        ": " + controlBottomPos + "\n");

    if (controlBottomPos > leftFlowLayoutPanel.ClientSize.Height) {
        controlBelowClientArea = true;
        lookingForControl = false;
    }
    controlIndex ++;
    if (controlIndex == leftFlowLayoutPanel.Controls.Count) {
        lookingForControl = false;
    }
}

下面是 debugTextBox 的输出,它是通过将四个连续的控件添加到控件 2(其 AutoSize 属性设置为 true)而产生的。控件 2 包含在 leftFlowLayoutPanel 中,通过单击其中包含的按钮将控件添加到其中:

  • 表单刚刚加载:
  • 控件底部位置 0: 3
  • 控件1的底部位置:128
  • 控制2的底部位置:253
  • 添加了第一个控件:
  • 控件底部位置 0: 3
  • 控件1的底部位置:128
  • 控制2的底部位置:253
  • 添加了第二个控件:
  • 控件底部位置 0: 3
  • 控件1的底部位置:226
  • 控制2的底部位置:351
  • 添加了第三个控件:
  • 控件底部位置 0: 3
  • 控件1的底部位置:324
  • 控制2的底部位置:449
  • 添加了第四个控件:
  • 控件底部位置 0: 3
  • 控件1的底部位置:422
  • 控制2的底部位置:547

添加第四个控件后,其中一个控件的底部超出其容器的 ClientArea (458) 的高度,并且 controlBelowClientArea 的值被分配为 true。

问题很清楚:我在布局事件期间从 FlowLayoutPanel 获得的值比最终的表单布局落后一步。在我将第四个控件添加到控件 1 之后,它的底部位置应该是 520。

我唯一想到的答案是 Layout 事件发生在正确设置所有属性的值之前。可能在执行任何内置布局逻辑之前调用它。如果是这种情况,是否有更合适的事件我可以处理?

4

4 回答 4

1

我唯一想到的答案是 Layout 事件发生在正确设置所有属性的值之前。

如果这确实是问题,您可以尝试以下解决方法。

using System;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            // Sign up for the FlowLayoutPanel Layout event.
            // When that event occurs, run your layout logic
            // using BeginInvoke to give the control a chance
            // to "settle down".
            //

            this.flowLayoutPanel1.Layout += delegate { this.BeginInvoke( ( Action )this.DoYourWorkHere ); };
        }

        void DoYourWorkHere()
        {
            //TODO: do your custom layout logic here.
        }
    }
}
于 2012-08-04T17:58:54.767 回答
0

我尝试了一个简单的应用程序,我测试一个按钮是否在 FlowLayoutPanel 的区域中,如果它显示一个文本框消息“out”,它可以工作:

 private void button2_Click(object sender, EventArgs e)
        {

                Button btn = new Button();
                flowLayoutPanel1.Controls.Add(btn);
            if((btn.Size.Height + btn.Location.Y) > (flowLayoutPanel1.Size.Height + flowLayoutPanel1.Location.Y))
            {
                textBox1.Text = "out";
            }
        }
于 2012-08-04T15:21:50.840 回答
0

试试这个

 while (lookingForControl) {
    controlBottomPos = controlsTemp[controlIndex].Size.Height  +
    controlsTemp[controlIndex].Location.Y ;

    debugTextBox.AppendText("Bottom position of control " + controlIndex + 
        ": " + controlBottomPos + "\n");

    if (controlBottomPos > leftFlowLayoutPanel.Size.Height + leftFlowLayoutPanel.Location.Y) {
        controlBelowClientArea = true;
        lookingForControl = false;
    }
    controlIndex ++;
    if (controlIndex == leftFlowLayoutPanel.Controls.Count) {
        lookingForControl = false;
    }
}
于 2012-08-04T16:08:25.230 回答
0

为了获取最新的属性值,我使用以下代码从 Layout 事件处理程序方法调用引用包含我的原始代码的方法的委托。

private void leftFlowLayoutPanel_Layout(object sender, LayoutEventArgs e) {
    if (this.IsHandleCreated) {
        this.BeginInvoke((Action)this.OriginalLayoutCode);
    }
}

我使用 IsHandleCreated 检查来避免可能的 InvalidOperationException。

于 2012-08-05T15:45:47.577 回答