0
votes

I am developing a WinForms app with a layered interface like this:

My UI Layout

Ignore Panel A. Next to that I have a TabControl with 2 tabs. On the TabPage of the 2nd tab, I have a few controls at the top for filtering data, and below that I have Panel B, a FlowLayoutPanel which displays a list of records from a database. Each record is displayed in a Panel C, which contains a variety of text fields, depending on the contents of the record.

The UI looks pretty good when it loads (but see problem #2, below). The first issue that I'm struggling with is properly handling a resize event for the main window. When the user drags the side of the main window to make it wider, the main form resizes the TabPage and Panel B, then it calls a method on Panel B to resize its contents. The controls at the top of the TabPage automatically spread out evenly across the top, in accordance with their settings. So far so good.

Panel B goes through its list of C Panels, adjusting the width of each. (Later I will add code for C Panel to adjust the widths of each text field accordingly.)

But at the moment, I'm stuck on 2 possibly related problems:

  1. I can't seem to get the C Panels to change their width. I had initially hoped that with the right settings of AutoSize, AutoScroll, etc. I could get what I want, but when that didn't work, I decided to add a resize event handler to take more control. That's not currently working right.

  2. Even prior to the resize, I set the width of Panel B to fit within the TabPage, and I set the FlowDirection of Panel B to FlowDirection.TopDown, yet once there are enough C Panels to exceed the height of Panel B, Panel B becomes double-width, and there is a 2nd column of C Panels in it. What I really want is to add a vertical scroll bar to scroll through the "TopDown" list.

When I had set AutoScroll to true for Panel B, I didn't get a vertical scroll bar (which I expected for a TopDown panel); instead I got a horizontal scroll bar & the panel grew to the right! So I turned off AutoScroll.

Here's some relevant code:

    class MainForm : Form
{
    private int priorHeight;
    private int priorWidth;
    private System.Windows.Forms.TabPage MyTabPage;
    private SelectableListPanel PanelB = null;

    ...

    private void OnResize(object sender, EventArgs e)
    {
        this.SuspendLayout();

        int vDiff = this.Height - priorHeight;
        int hDiff = this.Width - priorWidth;

        MyTabPage.Height += vDiff;
        MyTabPage.Width += hDiff;

        PanelB.Height += vDiff;
        PanelB.Width += hDiff;

        // tell PanelB to resize its record panels
        PanelB.PropagateResize(hDiff);

        ResumeLayout(false);
        PerformLayout();

        priorHeight = this.Height;
        priorWidth = this.Width;
    }
}

class SelectableListPanel : FlowLayoutPanel
{
    protected List<Panel> panels = new List<Panel>();

    public SelectableListPanel(List<Panel> Panels) : base()
    {
        FlowDirection = FlowDirection.TopDown;
        AutoScroll = false;
        AutoSize = false;
        panels = Panels;
    }

    ...

    public void PropagateResize(int hDiff)
    {
        foreach (Panel genPanel in panels)
        {
            genPanel.Width += hDiff;
            // TODO:  genPanel.PropagateResize(hDiff)
        }
    }
}

Any thoughts / suggestions?

1
Guess you just need to set the Anchor properties of the controls that should resize with the parent container. - LarsTech
Set the FlowLayoutPanel.FlowDirection to LeftToRight, with AutoSize = false and AutoScroll = true. Make some tests, to learn how to correctly use the anchors and docking features of your controls. - Jimi
@LarsTech, I tried going back over things to set the Anchor properties - Left, Right, Top on TabPage & Panel B; Left, Right on C Panels - but it didn't improve anything... - Todd Hoatson
@Jimi, not sure how setting FlowDirection to LeftToRight is supposed to help anything. Please explain. - Todd Hoatson
As described, if you want the child Controls of a FLP to flow top-down, you have to Set the FlowLayoutPanel.FlowDirection to LeftToRight, set AutoSize = false and AutoScroll = true. The child controls should be anchored to the FLP and the FLP needs to be anchored to the outer container: the Form itself or another container. The child Control will be attached to the LEFT. That's how it works. If you set FlowDirection = TopDown and AutoSize = true, the child Controls will flow from left to right (attached to the TOP), since the FLP will change its size to host new Controls. - Jimi

1 Answers

1
votes

Wanted to post some code which allowed me to test the suggestions I was receiving in the comments. My demo program does this:

enter image description here

And here's the code for it:

    public Form1()
{
    Panel BluePanel;
    Panel OrangePanel;
    Panel GreenPanel;
    List<Panel> PurplePanels;

    InitializeComponent();
    SuspendLayout();

    // Field 1
    TextBox f1 = new TextBox();
    f1.Text = "Main Form";
    f1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
    f1.Font = new Font("Microsoft Sans Serif", 14F, FontStyle.Regular,
       GraphicsUnit.Point, (byte) 0);
    f1.Location = new Point(12, 12);
    f1.Multiline = true;
    f1.Name = "Field1";
    f1.Size = new Size(460, 32);
    f1.TabIndex = 0;

    // BluePanel
    BluePanel = new Panel();
    BluePanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
    BluePanel.BackColor = Color.Blue;
    BluePanel.Location = new Point(12, 50);
    BluePanel.Name = "BluePanel";
    BluePanel.Size = new Size(460, 402);
    BluePanel.TabIndex = 1;

    // Field 2
    TextBox f2 = new TextBox();
    f2.Text = "Blue Panel";
    f2.Anchor = f1.Anchor;
    f2.Font = f1.Font;
    f2.Location = f1.Location;
    f2.Name = "Field2";
    f2.Size = new Size(BluePanel.Width - 24, f1.Height);
    f2.TabIndex = 0;
    BluePanel.Controls.Add(f2);

    // OrangePanel
    OrangePanel = new Panel();
    OrangePanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
    OrangePanel.BackColor = Color.Orange;
    OrangePanel.Location = new Point(f2.Left, f2.Bottom + 6);
    OrangePanel.Name = "OrangePanel";
    OrangePanel.Size = new Size(BluePanel.Width - 24, BluePanel.Height - (f2.Bottom + 6 + 12));
    OrangePanel.TabIndex = 1;
    BluePanel.Controls.Add(OrangePanel);

    // Field 3
    TextBox f3 = new TextBox();
    f3.Text = "Orange Panel";
    f3.Anchor = f1.Anchor;
    f3.Font = f1.Font;
    f3.Location = f1.Location;
    f3.Name = "Field3";
    f3.Size = new Size(OrangePanel.Width - 24, f1.Height);
    f3.TabIndex = 0;
    OrangePanel.Controls.Add(f3);

    // GreenPanel
//    GreenPanel = new FlowLayoutPanel();
//    GreenPanel.FlowDirection = FlowDirection.LeftToRight;
    GreenPanel = new Panel();
    GreenPanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
    GreenPanel.AutoScroll = true;
    GreenPanel.AutoSize = false;
    GreenPanel.BackColor = Color.Green;
    GreenPanel.Location = new Point(f3.Left, f3.Bottom + 6);
    GreenPanel.Name = "GreenPanel";
    GreenPanel.Size = new Size(OrangePanel.Width - 24, OrangePanel.Height - (f3.Bottom + 6 + 12));
    GreenPanel.TabIndex = 1;
    OrangePanel.Controls.Add(GreenPanel);

    // PurplePanels
    PurplePanels = new List<Panel>();
    for (int i = 0; i < 10; i++)
    {
        Panel PurplePanel = new Panel();
        PurplePanel.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;

        PurplePanel.BackColor = Color.Purple;
        PurplePanel.Size = new Size(GreenPanel.Width - 24, 32 + 24);
        PurplePanel.Location = new Point(12, 6 + (i * (32 + 24 + 6)));
        PurplePanel.Name = "PurplePanel" + i.ToString();
        PurplePanel.TabIndex = i;

        // Fields
        TextBox fi = new TextBox();
        fi.Text = "Purple Panel " + i.ToString();
        fi.Anchor = f1.Anchor;
        fi.Font = f1.Font;
        fi.Location = f1.Location;
        fi.Name = "Fieldi" + i.ToString();
        fi.Size = new Size(PurplePanel.Width - 24, f1.Height);
        fi.TabIndex = 0;
        PurplePanel.Controls.Add(fi);

        GreenPanel.Controls.Add(PurplePanel);
        PurplePanels.Add(PurplePanel);
    }

    ResumeLayout(false);
    PerformLayout();
}

To see what is different with the FlowLayoutPanel, simply un-comment the relevant lines in the Green Panel section, and comment out the "GreenPanel = new Panel();" line. There you will see that FlowDirection.LeftToRight does not produce the desired result.

I also want to give a shout out to @Jimi and @LarsTech for pointing me in the right direction.