Winforms: Location properties got during Layout event of FlowLayoutPanel don't reflect updated layout. Why is this?

StackOverflow https://stackoverflow.com/questions/11809523

Question

I am using a non-automatic VScrollBar control for a FlowLayoutPanel containing UserControls.

I need to find out whether any of the controls in my FlowLayoutPanel are positioned outside its client area. I want to use this information to determine whether the VScrollBar is visible or not. I've put following code in the FlowLayoutPanel's Layout event handler method:

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

Here is the output to debugTextBox resulting from adding four successive controls to control 2, whose AutoSize property is set to true. Control 2 is contained by leftFlowLayoutPanel and the controls are added to it by clicking a button contained within it:

  • Form has just loaded:
  • Bottom position of control 0: 3
  • Bottom position of control 1: 128
  • Bottom position of control 2: 253
  • First control added:
  • Bottom position of control 0: 3
  • Bottom position of control 1: 128
  • Bottom position of control 2: 253
  • Second control added:
  • Bottom position of control 0: 3
  • Bottom position of control 1: 226
  • Bottom position of control 2: 351
  • Third control added:
  • Bottom position of control 0: 3
  • Bottom position of control 1: 324
  • Bottom position of control 2: 449
  • Fourth control added:
  • Bottom position of control 0: 3
  • Bottom position of control 1: 422
  • Bottom position of control 2: 547

After the fourth control is added, one of the control's bottoms exceeds the Height of its container's ClientArea (458) and controlBelowClientArea is assigned the value of true.

The problem is clear: The values I get from my FlowLayoutPanel during the Layout Event are one step behind the resulting layout of the form. After I added the fourth control to control 1, it's bottom position should be 520.

The only answer that's occurred to me is that the Layout event happens before all the properties' values are properly set. Perhaps it is called before any built-in layout logic is carried out. If this is the case, is there a more suitable event I could handle?

Était-ce utile?

La solution 4

In order to get property values which were up-to-date, I used the following code to invoke a delegate referring to a method containing my original code, from a Layout event handler method.

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

I used the IsHandleCreated check to avoid a possible InvalidOperationException.

Autres conseils

The only answer that's occurred to me is that the Layout event happens before all the properties' values are properly set.

If that is indeed the problem, you could try the following as a workaround.

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

i try a simple application where i test if a button is in area of FlowLayoutPanel if true it show a textbox message "out", it works:

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

try this

 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;
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top