C# 如何调整TableLayoutPanel以按高度和重量包装内容?(动态)
我创建了将用作弹出窗口的C# 如何调整TableLayoutPanel以按高度和重量包装内容?(动态),c#,winforms,C#,Winforms,我创建了将用作弹出窗口的表单。我需要这个弹出窗口包含标题,进度条和百分比文本 因此,出于这个目的,我选择在表单中使用TableLayoutPanel作为控件 有一段代码可以动态创建所有这些视图。对于现在的测试,我使用lable而不是真正的progressbar实现 public partial class TestFormDeleteIt : Form { public TestFormDeleteIt() { Initialize
表单。我需要这个弹出窗口包含标题,进度条和百分比文本
因此,出于这个目的,我选择在表单中使用TableLayoutPanel
作为控件
有一段代码可以动态创建所有这些视图。对于现在的测试,我使用lable而不是真正的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;
}
}
因此,正如您所看到的,我创建了TableLayoutPanel
,将其除以行和列,并为每个视图设置Dock=DockStyle.Fill
,因为我不想使用硬代码固定大小
我期望的是-每个视图都会填充tablelayout中的单元格,根表单本身会通过保存所有视图的talbelayout来调整您的大小
但实际上我得到了这个结果:
根表单不包装内容,看起来它有固定的大小,tablelayout尝试填充这个根表单大小,但我设置了AutoSize=true代码>,但它不影响
我做错了什么
编辑
谢谢,@Jimi现在看起来好多了
我还补充说
MinimumSize = new System.Drawing.Size(600, Height)
到TLP,但问题是-正如你们所看到的,每一行都有最小高度。它看起来像是每行之间的空间。为什么会这样
EDIT2
我想注意,如果我改变这个
panel.Controls.Add(
new Label()
{
Text = "state",
Dock = DockStyle.Fill
},
/*column*/ 0, /*row*/ 0);
对此
var label1 = new Label()
{
Text = "state",
Dock = DockStyle.Fill
};
panel.SetRow(label1, 0);
panel.SetColumn(label1, 0);
它不起作用。。。我做错了什么
这是我的代码
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
};
}
问题是-即使在我的表单中将静态宽度设置为200->MinimumSize=new System.Drawing.Size(200,0)
,当我打开它时,我看到它需要大约1000
为什么会发生这种情况?场景:
- 裸骨形状,未应用特定尺寸。无子控件李>
- 是在运行时从头开始构建的。没有具体尺寸
- 创建两行两列时,将“大小模式”设置为“百分比”
- 三个控件从头创建并添加到TableLayoutPanel的三个单元格中
TableLayoutPanel必须根据新内容调整自身大小,新内容没有特定大小(应用于Windows窗体控件的默认大小除外),而不会挤出新的子控件
- 将TableLayoutPanel添加到其控件集合后,窗体必须将自身大小自动调整为其(唯一)子控件的大小,保持新设置的最小宽度,但没有最小或最大高度(因此,如果需要,它可以垂直扩展,但不能水平扩展)
- 最后,自动调整大小的TableLayoutPanel必须停靠在自动调整大小的表单容器中,所有部件都需要协作以生成预期的布局
如何继续:
操作顺序将明确决定最终结果
表单初始化:它的构造函数调用标准的InitializeComponent()方法。没有子控件,因此实际上没有任何布局。表单只需设置设计器中定义的大小李>
现在,我们指示表单根据其内容自动调整大小,并且允许它同时增大和缩小大小以完成此任务。表单现在实际上不会执行任何操作,因为此时无法执行布局(除非使用PerformLayout()
方法明确指示)
我们设置了一个最小尺寸,限制其宽度,但不限制其高度(设置MinimumSize=new Size(200,0)
,我们定义了一个最小宽度,但高度尺寸可以自由增长,也可以收缩,这里-将0
设置为值,表示没有限制)李>
现在使用默认大小创建TableLayoutPanel及其子控件(Windows窗体控件在创建时具有默认大小)。标签将自动调整其文本大小:这是默认行为李>
将所有子控件添加到TLP后,将指示TLP自动调整自身大小,同时指定它可以增长和收缩以执行布局。
6将TableLayoutPanel添加到表单容器中。现在,当控件添加到控件集合时,内部方法指示ContainerControlSuspendLayout()
,定位新控件并ResumeLayou()
(由于刚刚发生了这种情况,因此不执行子控件的布局):此时,指示自动调整其内容大小,将计算其首选大小
,然后自动调整其自身大小以适应新内容李>
TableLayoutPanel
现在设置为停靠到父容器。容器的大小已经自动调整为TableLayoutPanel
的大小,因此TLP只是将其锚定固定为表单的当前大小李>
最终布局将在显示窗体之前执行:无论如何,此时,所有涉及的控件都已按照指示进行了大小和位置调整
额外的:
► TableLayoutPanel的和被显式调用。这两种方法的备注部分解释了原因:
此方法将表布局重新应用于
TableLayoutPanel
在当前上下文中,调用这些方法是一个优势。它不是严格需要的,因为我们只是在TLP中添加控件,从不删除任何控件。
但是,当TLP设置为自动调整其内容(这适用于当前上下文)时,向TLP添加控件并从TLP中移除控件时,TLP实际上不会按预期执行布局:在大多数情况下(是的,不总是…),当移除控件(移除或处置,结果相同)时,单元格将保持其原始大小.
关于这一问题的一些注释可在此处找到:
这段代码(不同的语言,但对r来说很简单
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);
}
}
}