I created a Form that I am going to use as pop-up.
I need that this pop-up contains title, ProgressBar and percentage text.
So, for this purpose, I choose to use TableLayoutPanel
as a control in my Form.
All these UI elements are created in dynamically. For test now I am using Label instead of real ProgressBar.
public partial class TestFormDeleteIt : Form
{
public TestFormDeleteIt()
{
InitializeComponent();
AutoSize = true;
var flp = CreateTableLayoutPanel();
Controls.Add(flp);
}
private Control CreateTableLayoutPanel()
{
// TableLayoutPanel Initialization
var panel = new TableLayoutPanel
{
ColumnCount = 2,
RowCount = 2,
Dock = DockStyle.Fill
};
//Adjust column size in percentage
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 70F));
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 30F));
//Adjust row size in percentage
panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
//Fill content
panel.Controls.Add(
new Label()
{
Text = "state",
Dock = DockStyle.Fill
},
/*column*/ 0, /*row*/ 0);
panel.Controls.Add(
new Label()
{
Text = "ProgressBar",
Dock = DockStyle.Fill
},
/*column*/ 0, /*row*/ 1);
panel.Controls.Add(
new Label()
{
Text = "100%",
Dock = DockStyle.Fill
},
/*column*/ 1, /*row*/ 1);
return panel;
}
}
So, as you can see I create TableLayoutPanel
divided by rows and columns and for each view that it holds I set Dock = DockStyle.Fill
, because I don't want to hardcode a fixed size.
What am I expecting is that each UI element fills a Cell in the TableLayoutPanel and the parent Form itself will adjust its size by the TableLayoutPanel that holds all the other Controlss.
But actually I get this result:
The Parent Form doesn't wrap content, it looks like it has fixed size and the TableLayoutPanel tries to fill the Form ClientArea. I've set AutoSize = true;
, but it has no visible affect.
What am I doing wrong?
EDIT
Thanks, @Jimi now it looks like much better
I also added
MinimumSize = new System.Drawing.Size(600, Height)
to TLP, but question is - as you can see each row has like min height. And it looks like space between each row. Why is it happens?
EDIT2
I would like to notice that if I change this
panel.Controls.Add(
new Label()
{
Text = "state",
Dock = DockStyle.Fill
},
/*column*/ 0, /*row*/ 0);
to this:
var label1 = new Label()
{
Text = "state",
Dock = DockStyle.Fill
};
panel.SetRow(label1, 0);
panel.SetColumn(label1, 0);
it doesn't work... What am I doing wrong?
and here is my code now
public partial class TestFormDeleteIt : Form
{
public TestFormDeleteIt()
{
InitializeComponent();
AutoSize = true;
AutoSizeMode = AutoSizeMode.GrowAndShrink;
MinimumSize = new System.Drawing.Size(200, 0);
var flp = CreateTableLayoutPanel();
Controls.Add(flp);
}
private TableLayoutPanel CreateTableLayoutPanel()
{
// TableLayoutPanel Initialization
var panel = new TableLayoutPanel
{
ColumnCount = 2,
RowCount = 2,
Dock = DockStyle.Fill
};
//Adjust column size in percentage
panel.ColumnStyles.Clear();
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 90F));
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 10F));
//Adjust row size in percentage
panel.RowStyles.Clear();
panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
//Fill content
panel.Controls.Add(
new Label()
{
Text = "state",
Dock = DockStyle.Fill
},
/*column*/ 0, /*row*/ 0);
panel.Controls.Add(
CreateProgressBar(),
/*column*/ 0, /*row*/ 1);
panel.Controls.Add(
new Label()
{
Text = "100%",
Dock = DockStyle.Fill
},
/*column*/ 1, /*row*/ 1);
panel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
panel.AutoSize = true;
return panel;
}
private Control CreateProgressBar() => new ProgressBar()
{
Visible = true,
Dock = DockStyle.Top
};
}
Problem is - that even if I set static width as 200 -> MinimumSize = new Size(200, 0)
in my Form, when I open it I see that it takes like 1000
.
Why is it happens?
The scenario:
How to proceed:
The sequence of the operations will clearly determine the final result.
PerformLayout()
method)MinimumSize = new Size(200, 0)
, we define a minimum Width, but the Height dimension is free to grow and also shrink, here - setting 0
as value, means no restrictions).SuspendLayout()
, position the new Control and ResumeLayou()
(without also performing the Layout of the child Controls, since this has just happened): at this point, the Form, instructed to AutoSize to its content, will calculate its PreferredSize
and then auto-size itself to the new content.TableLayoutPanel
is now set to Dock to the parent Container. The Container is already auto-sized to the size of the TableLayoutPanel
, so the TLP just fixes its anchors to the current Size of the Form.The final Layout will be performed before the Form is shown: anyway, at this point, all the Controls involved are already sized and positioned as instructed.
Extra:
▶ The TableLayoutPanel's SetColumn() and SetRow() are called explicitly. The reason is partailly explained in the Remarks section of the two methods:
This method reapplies the table layout to all controls in the TableLayoutPanel.
In the current context, calling these methods is a plus. It's not strictly needed, because we just add Controls to the TLP, never remove one.
But, when Controls are added to and removed from the TLP while the TLP is set to AutoSize to its content (this applies to the current context), the TLP won't actually perform the Layout as expected: the Cells will, in most cases (yes, not always...) maintain their original Size when a Control is removed (removed or disposed, the result is the same).
Some notes on the matter are found here:
This code (different language but simple to read) can easily tested to reproduce the problem
Dynamic TableLayoutPanel Controls Keep Border Width
▶ The ColumnStyles and RowStyles are cleared and new styles are added:
- The original code actually adds new styles without removing the existing, default, ones: this can and will generate a layout problem in some situations. Some notes on the matter here:
Remove Row inside TableLayoutPanel makes a layout problem
Center multiple rows of controls in a FlowLayoutPanel
public partial class TestFormDeleteIt : Form
{
protected internal ProgressBar pBar = null;
protected internal Label lbl2 = null;
public TestFormDeleteIt()
{
InitializeComponent();
this.AutoSize = true;
this.AutoSizeMode = AutoSizeMode.GrowAndShrink;
this.MinimumSize = new Size(200, 0);
var tlp = CreateTableLayoutPanel();
tlp.AutoSizeMode = AutoSizeMode.GrowAndShrink;
tlp.AutoSize = true;
this.Controls.Add(tlp);
tlp.Dock = DockStyle.Fill;
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Task.Run(() => UpdateProgress());
}
private TableLayoutPanel CreateTableLayoutPanel()
{
var panel = new TableLayoutPanel { ColumnCount = 2, RowCount = 2,
CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
};
panel.ColumnStyles.Clear();
panel.RowStyles.Clear();
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 70F));
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 30F));
panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
var lbl1 = new Label() { Text = "state", Dock = DockStyle.Fill };
panel.Controls.Add(lbl1);
panel.SetColumn(lbl1, 0);
panel.SetRow(lbl1, 0);
pBar = new ProgressBar() { Dock = DockStyle.Top };
panel.Controls.Add(pBar);
panel.SetColumn(pBar, 0);
panel.SetRow(pBar, 1);
lbl2 = new Label() { Text = "0%", Dock = DockStyle.Fill };
panel.Controls.Add(lbl2);
panel.SetColumn(lbl2, 1);
panel.SetRow(lbl2, 1);
return panel;
}
private async Task UpdateProgress()
{
for (int i = 1; i <= 100; i++) {
BeginInvoke(new Action(() => {
pBar.Value = i;
lbl2.Text = (i / 100.0).ToString("P");
}));
await Task.Delay(50);
}
}
}