如何调整 TableLayoutPanel 以按高度和重量包裹内容?(动态) [英] How to adjust TableLayoutPanel to wrap content by height and weight? (dynamically)

查看:45
本文介绍了如何调整 TableLayoutPanel 以按高度和重量包裹内容?(动态)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个用作弹出窗口的表单.
我需要这个弹出窗口包含标题、进度条和百分比文本.

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.

因此,为此,我选择使用 TableLayoutPanel 作为我表单中的控件.

So, for this purpose, I choose to use TableLayoutPanel as a control in my Form.

所有这些 UI 元素都是动态创建的.现在为了测试,我使用 Label 而不是真正的 ProgressBar.

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

所以,正如你所看到的,我创建了 TableLayoutPanel 按行和列划分,并为它持有的每个视图设置了 Dock = DockStyle.Fill,因为我不不想硬编码固定大小.

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.

我期望的是每个 UI 元素都填充 TableLayoutPanel 中的一个单元格,并且父 Form 本身将通过包含所有其他 Controlss 的 TableLayoutPanel 调整其大小.

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:

父表单不包装内容,它看起来像固定大小,并且 TableLayoutPanel 尝试填充表单 ClientArea.我已经设置了 AutoSize = true;,但它没有明显的影响.

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.

我做错了什么?

编辑

谢谢,@Jim 现在看起来好多了

Thanks, @Jimi now it looks like much better

我也加了

MinimumSize = new System.Drawing.Size(600, Height)

到 TLP,但问题是 - 正如您所看到的,每一行都有最小高度.它看起来像每行之间的空间.为什么会这样?

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

为此:

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?

这是我的代码

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 Size(200, 0) 在我的表单中,当我打开它时,我看到它需要 1000.

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.

为什么会这样?

推荐答案

场景:

  • 一个简单的表格,没有应用特定的尺寸.没有子控件.
  • TableLayoutPanel 是从在运行时划伤.无具体尺寸
    • 在大小模式设置为百分比的情况下创建了两行和两列
    • 从头开始创建三个控件并添加到三个 TableLayoutPanel 的单元格中
      TableLayoutPanel 必须将自身调整为新内容的大小,该内容没有特定大小(除了应用于 Windows 窗体控件的默认大小),不会挤压新子控件的存在
    • A bare-bones Form, no specific dimensions applied. No child controls.
    • A TableLayoutPanel is build from scratch at run-time. No specific dimensions
      • Two Rows and two Columns are created with size mode set to percentage
      • Three Control are created from scratch and added to three of the TableLayoutPanel's Cells
        The TableLayoutPanel must resize itself to the new content, which doesn't have a specific size (except the default size applied to the Windows Forms Controls), without squeezing out of existence the new child Controls

      如何进行:

      操作的顺序将清楚地决定最终结果.

      The sequence of the operations will clearly determine the final result.

      1. Form 初始化:它的构造函数调用标准的 InitializeComponent() 方法.没有子控件,所以实际上没有什么可布局的.表单将简单地设置在设计器中定义的大小.
      2. 我们现在指示 Form 自动调整其内容的大小,并且允许它增大和缩小其大小以完成此任务.表单现在实际上不会做任何事情,因为它此时无法执行其布局(除非明确指示,使用 PerformLayout() 方法)
      3. 我们设置了一个最小尺寸,限制了它的宽度,而不是它的高度(设置MinimumSize = new Size(200, 0),我们定义了一个最小宽度,但是高度维度可以自由增长也可以收缩,这里 - 将 0 设置为值,意味着 没有限制).
      4. 现在使用默认大小创建了 TableLayoutPanel 及其子控件(Windows 窗体控件在创建时具有默认大小).标签将自动调整到其文本的大小:这是默认行为.
      5. 在将所有子控件添加到 TLP 后,TLP 被指示自动调整大小,同时指定它可以增长和缩小以执行布局.6 TableLayoutPanel 被添加到 Form 容器中.现在,当一个 Control 添加到 Controls 集合时,内部方法会指示 ContainerControl SuspendLayout(),定位新的 Control 和 ResumeLayou()(不还执行子控件的布局,因为这刚刚发生):此时,被指示自动调整其内容的表单将计算其 PreferredSize 然后根据新内容自动调整大小.
      6. TableLayoutPanel 现在设置为停靠到父容器.Container 已经自动调整到 TableLayoutPanel 的大小,所以 TLP 只是将其锚点固定到表单的当前大小.
      1. The Form initializes: it's construtor calls the standard InitializeComponent() method. There are no child Controls, so there's actually nothing to layout. The Form will simply set the Size defined in the Designer.
      2. We now instruct the Form to AutoSize to its content and also that it's allowed to both grow and shrink its Size to accomplish this task. The Form won't actually do anything right now, since it cannot perform its Layout at this time (unless explicitly instructed, using the PerformLayout() method)
      3. We set a minimum Size, constraining its Width, but not its Height (setting 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).
      4. The TableLayoutPanel and its child Controls are now created, using default Sizes (Windows Forms Controls have a default Size when created). The Labels will AutoSize to the size of their Text: this is the default behavior.
      5. After all child Controls are added to the TLP, the TLP is instructed to AutoSize itself, also specifying that it can grow and shrink to perform the Layout. 6 The TableLayoutPanel is added to the Form container. Now, when a Control is added to the Controls collection, the internal method instructs the ContainerControl to 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.
      6. The 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.

      额外:

      ► TableLayoutPanel 的 SetColumn()SetRow() 被显式调用.原因在两种方法的备注部分有部分说明:

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

      在当前上下文中,调用这些方法是一个加号.它不是严格需要的,因为我们只是将控件添加到 TLP,从不删除.
      但是,当将控件添加到 TLP 或从 TLP 中删除时,TLP 设置为其内容的 AutoSize(这适用于当前上下文),TLP 实际上不会按预期执行布局:在大多数情况下,单元格会(是的,并不总是......)当控件被移除(移除或处置,结果相同)时保持其原始大小.

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

      有关此事的一些说明可在此处找到:
      此代码(不同语言但易于阅读)可以轻松测试以重现问题
      动态 TableLayoutPanel 控件保持边框宽度

      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

      ColumnStylesRowStyles 被清除并且是新的添加样式:
      - 原始代码实际上添加了新样式而不删除现有的默认样式:这在某些情况下会并且会产生布局问题.关于此事的一些说明:

      ► 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:

      删除 TableLayoutPanel 中的 Row 会导致布局问题
      将 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);
              }
          }
      }
      

      这篇关于如何调整 TableLayoutPanel 以按高度和重量包裹内容?(动态)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆