Winforms:FlowLayoutPanel的Layout事件期间获得的位置属性don';t反映更新后的布局.

本文关键字:布局 更新 don 位置 事件 Layout FlowLayoutPanel Winforms 属性 | 更新日期: 2024-10-24 21:34:38

我正在为包含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;
    }
}

以下是向控件2添加四个连续控件所得到的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。

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

我想到的唯一答案是Layout事件发生在所有属性的值都正确设置之前。也许它是在执行任何内置布局逻辑之前调用的。如果是这样的话,有没有更适合我处理的事件?

Winforms:FlowLayoutPanel的Layout事件期间获得的位置属性don';t反映更新后的布局.

我想到的唯一答案是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.
        }
    }
}

我尝试了一个简单的应用程序,在这个应用程序中,我测试按钮是否在FlowLayoutPanel的区域中。如果为true,它会显示一条文本框消息"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";
            }
        }

尝试这个

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

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

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

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