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添加到表单容器中。现在,当控件添加到控件集合时,内部方法指示ContainerControl
    SuspendLayout()
    ,定位新控件并
    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);
            }
        }
    }