【问题标题】:Remove Row inside TableLayoutPanel makes a layout problem删除 TableLayoutPanel 中的 Row 会导致布局问题
【发布时间】:2019-03-13 09:16:41
【问题描述】:

我有一个带有TableLayoutPanel 的 WinForms 应用程序;这是定义代码:

tableLayoutPanel1 = new TableLayoutPanel();
tableLayoutPanel1.Dock = DockStyle.Fill;
tableLayoutPanel1.AutoScroll = true;

tableLayoutPanel1.RowCount = users.Count + 1;
tableLayoutPanel1.ColumnCount = 1;
tableLayoutPanel1.GrowStyle = TableLayoutPanelGrowStyle.FixedSize;
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));

foreach (String user in users)
{
    tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 600F));
}
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 600F));

int index = 0;
foreach (String user in users)
{
    AddDockedControl(index, user);
    index++;
}
AddDockedControl(index, null);

panel1.Controls.Add(tableLayoutPanel1);

private void AddDockedControl(int row, String userName)
{
    AccountRowUC newUser = new AccountRowUC(this, userName, row);
    newUser.BorderStyle = BorderStyle.FixedSingle;
    newUser.Dock = DockStyle.Top;
    tableLayoutPanel1.Controls.Add(newUser, 0, row);
}

现在,当我想删除其中一行时,我正在使用以下代码:

public void RemoveRowAtIndex(int index)
{
    if (index >= tableLayoutPanel1.RowCount)
        return;

    // delete all controls of row that we want to delete
    for (int i = 0; i < tableLayoutPanel1.ColumnCount; i++)
    {
        var control = tableLayoutPanel1.GetControlFromPosition(i, index);
        tableLayoutPanel1.Controls.Remove(control);
    }

    // move up row controls that comes after row we want to remove
    for (int i = index + 1; i < tableLayoutPanel1.RowCount; i++)
    {
        for (int j = 0; j < tableLayoutPanel1.ColumnCount; j++)
        {
            var control = tableLayoutPanel1.GetControlFromPosition(j, i);
            if (control != null)
                tableLayoutPanel1.SetRow(control, i - 1);
        }
    }

    // remove last row

    tableLayoutPanel1.RowStyles.RemoveAt(tableLayoutPanel1.RowCount - 1);
    //tableLayoutPanel1.RowStyles.RemoveAt(index);
    tableLayoutPanel1.RowCount--;
}

问题是当我删除一个 Row 时,表格底部会留下一个很大的空间:TableLayoutPanel 不会回收panel1 的大小。

【问题讨论】:

    标签: c# .net winforms user-controls tablelayoutpanel


    【解决方案1】:

    基于 cmets 中描述的布局的解决方案和之前发布的此答案:
    Center multiple rows of controls in a FlowLayoutPanel

    说明:
    (本文底部提供的测试表单的完整代码)

    1. 创建一个新表单(此处命名为 frmTLPTest1
    2. 添加两个面板。一个用于承载一些按钮,另一个将是 TableLayoutPanel 的容器。
    3. 将容器面板设置为AutoScroll = trueAutoSizeMode = AutoSizeMode.GrowAndShrink,设置所有锚点(左、上、右、下)
    4. 在 Container 面板中,放置一个新的 TableLayoutPanel:将其设置为 AutoSize = trueAutoSizeMode = AutoSizeMode.GrowAndShrinkDock = DockStyle.Top
    5. 从 TableLayoutPanel 中删除所有行和列,除了每个行和列(不能全部删除)。将两者的尺寸设置为AutoSize

    重要说明(也在链接答案中报告):

    在 Form 构造函数中,删除了其中一个 RowStyles。这是 重要:TLP 将保留 2 个 RowStyles。一是应用于 现有行;第二种样式将应用于您的第一行 添加:仅对第一个,而不是其他。如果没有这种风格 删除,它会影响布局。

    用于TableLayoutPanel的Add Rows/Remove Rows的核心方法,使用FlowLayoutPanel作为TLP Row内容,最终也可以作为其他控件的Container。

    TlpAddRow(TableLayoutPanel tlp, bool addRowCount) 方法:
    将新的 FlowLayoutPanel 添加到指定的 TableLayoutPanel 的 Cell 中,并在请求时添加新的 Row。
    由于设计器不允许删除所有行,因此第一个 Row (FlowLayoutPanel) 不得增加行数:addRowCount 参数将设置为 false

    private Control TlpAddRow(TableLayoutPanel tlp, bool addRowCount)
    {
        var flp = new FlowLayoutPanel() {
            Anchor = AnchorStyles.Top | AnchorStyles.Bottom,
            AutoSize = true,
            AutoSizeMode = AutoSizeMode.GrowAndShrink,
        };
    
        tlp.SuspendLayout();
        if (addRowCount) tlp.RowCount += 1;
        tlp.Controls.Add(flp, 0, tlp.RowCount - 1);
        tlp.ResumeLayout(true);
        return flp;
    }
    

    TLPRemoveRow(TableLayoutPanel tlp, Control control) 方法(重载):

    允许从指定的 TableLayoutPanel 中删除行。要删除的 Row 可以从用作 Row Container 的 Control 派生(这里是 FlowLayoutPanel,但它可以是 Panel、另一个 TableLayoutPanel 或其他一些类型的 Container 控件)。
    也可以通过直接指定 Row 索引来移除 Row。

    private void TLPRemoveRow(TableLayoutPanel tlp, Control control)
    {
        int ctlRow = tlp.GetRow(control);
        TLPRemoveRow(tlp, ctlRow);
    }
    
    private void TLPRemoveRow(TableLayoutPanel tlp, int row)
    {
        if (row < tlp.RowCount - 1) {
            for (int i = row; i < tlp.RowCount - 1; i++) {
                tlp.SetRow(tlp.GetControlFromPosition(0, i + 1), i);
            }
        }
        tlp.RowCount -= 1;
    }
    

    此布局的视觉结果:

    由于通过测试而不是解释更容易理解它的工作原理,因此这里是表单的完整布局:

    测试表格 (frmTLPTest1):

    using System.Drawing;
    using System.Linq;
    using System.Windows.Forms;
    
    public partial class frmTLPTest1 : Form
    {
        public frmTLPTest1()
        {
            InitializeComponent();
            tlp1.RowStyles.RemoveAt(1);
        }
    
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            TlpAddRow(tlp1, false);
        }
    
        Random rnd = new Random();
        Size[] sizes = new Size[] { new Size(75, 75), new Size(100, 100), new Size(125, 125)};
        Color[] colors = new Color[] { Color.Red, Color.LightGreen, Color.YellowGreen, Color.SteelBlue };
        Control selectedObject = null;
        Control selectedParent = null;
    
        private void btnAddControl_Click(object sender, EventArgs e)
        {
            Size size = new Size(125, 125);
            if (chkRandom.Checked) size = sizes[rnd.Next(sizes.Length)];
            
            var pBox = new PictureBox() {
                Anchor = AnchorStyles.None,
                BackColor = colors[rnd.Next(colors.Length)],
                MinimumSize = size,
                Size = size
            };
    
            bool drawborder = false;
            pBox.MouseEnter += (s, evt) => { drawborder = true;  pBox.Invalidate(); };
            pBox.MouseLeave += (s, evt) => { drawborder = false; pBox.Invalidate(); };
            pBox.MouseDown += (s, evt) => { selectedParent = pBox.Parent;
                                            selectedObject = pBox;  pBox.Invalidate();
            };
            pBox.Paint += (s, evt) => {
                if (drawborder) {
                    ControlPaint.DrawBorder(evt.Graphics, pBox.ClientRectangle, 
                                            Color.White, ButtonBorderStyle.Solid);
                }
            };
    
            if (tlp1.RowCount == 0) TlpAddRow(tlp1, true); 
    
            var ctl = tlp1.GetControlFromPosition(0, tlp1.RowCount - 1);
            int overallWith = 0;
            if (ctl.Controls?.Count > 0) {
                overallWith = ctl.Controls.OfType<Control>().Sum(c => c.Width + c.Margin.Left + c.Margin.Right);
            }
            overallWith += ctl.Margin.Right + ctl.Margin.Left + pBox.Size.Width + pBox.Margin.Left + pBox.Margin.Right;
    
            if (overallWith >= tlp1.Width) {
                ctl = TlpAddRow(tlp1, true);
            }
            ctl.Controls.Add(pBox);
        }
    
        private void btnRemoveRow_Click(object sender, EventArgs e)
        {
            if (selectedParent is null) return;
            if (selectedParent.Controls.Count > 0) {
                for (int i = 0; i == selectedParent.Controls.Count - 1; i++) {
                    selectedParent.Controls[i].Dispose();
                }
            }
            TLPRemoveRow(tlp1, selectedParent);
            selectedParent.Dispose();
        }
    
        private void btnRemoveControl_Click(object sender, EventArgs e)
        {
            if (selectedObject is null) return;
            Control parent = selectedObject.Parent;
            selectedObject.Dispose();
    
            if (parent?.Controls.Count == 0) {
                TLPRemoveRow(tlp1, parent);
                parent.Dispose();
            }
        }
    
        private Control TlpAddRow(TableLayoutPanel tlp, bool addRowCount)
        {
            var flp = new FlowLayoutPanel() {
                Anchor = AnchorStyles.Top | AnchorStyles.Bottom,
                AutoSize = true,
                AutoSizeMode = AutoSizeMode.GrowAndShrink,
            };
    
            tlp.SuspendLayout();
            if (addRowCount) tlp.RowCount += 1;
            tlp.Controls.Add(flp, 0, tlp.RowCount - 1);
            tlp.ResumeLayout(true);
            return flp;
        }
    
        private void TLPRemoveRow(TableLayoutPanel tlp, Control control)
        {
            int ctlRow = tlp.GetRow(control);
            TLPRemoveRow(tlp, ctlRow);
        }
    
        private void TLPRemoveRow(TableLayoutPanel tlp, int row)
        {
            if (row < tlp.RowCount - 1) {
                for (int i = row; i < tlp.RowCount - 1; i++) {
                    tlp.SetRow(tlp.GetControlFromPosition(0, i + 1), i);
                }
            }
            tlp.RowCount -= 1;
        }
    }
    

    测试表单设计器

    partial class frmTLPTest1
    {
        private System.ComponentModel.IContainer components = null;
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null)) {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
    
        private void InitializeComponent()
        {
            this.panToolbar = new System.Windows.Forms.Panel();
            this.btnRemoveRow = new System.Windows.Forms.Button();
            this.chkRandom = new System.Windows.Forms.CheckBox();
            this.btnRemoveControl = new System.Windows.Forms.Button();
            this.btnAddControl = new System.Windows.Forms.Button();
            this.panBackground = new System.Windows.Forms.Panel();
            this.tlp1 = new System.Windows.Forms.TableLayoutPanel();
            this.panToolbar.SuspendLayout();
            this.panBackground.SuspendLayout();
            this.SuspendLayout();
            // 
            // panToolbar
            // 
            this.panToolbar.BackColor = System.Drawing.Color.DarkOliveGreen;
            this.panToolbar.Controls.Add(this.btnRemoveRow);
            this.panToolbar.Controls.Add(this.chkRandom);
            this.panToolbar.Controls.Add(this.btnRemoveControl);
            this.panToolbar.Controls.Add(this.btnAddControl);
            this.panToolbar.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.panToolbar.Location = new System.Drawing.Point(0, 359);
            this.panToolbar.Name = "panToolbar";
            this.panToolbar.Size = new System.Drawing.Size(552, 55);
            this.panToolbar.TabIndex = 2;
            // 
            // btnRemoveRow
            // 
            this.btnRemoveRow.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
            this.btnRemoveRow.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(64)))), ((int)(((byte)(0)))));
            this.btnRemoveRow.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(64)))), ((int)(((byte)(0)))));
            this.btnRemoveRow.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.btnRemoveRow.ForeColor = System.Drawing.Color.White;
            this.btnRemoveRow.Location = new System.Drawing.Point(261, 11);
            this.btnRemoveRow.Name = "btnRemoveRow";
            this.btnRemoveRow.Size = new System.Drawing.Size(119, 34);
            this.btnRemoveRow.TabIndex = 4;
            this.btnRemoveRow.Text = "Remove Row";
            this.btnRemoveRow.UseVisualStyleBackColor = false;
            this.btnRemoveRow.Click += new System.EventHandler(this.btnRemoveRow_Click);
            // 
            // chkRandom
            // 
            this.chkRandom.AutoSize = true;
            this.chkRandom.ForeColor = System.Drawing.Color.White;
            this.chkRandom.Location = new System.Drawing.Point(446, 20);
            this.chkRandom.Name = "chkRandom";
            this.chkRandom.Size = new System.Drawing.Size(94, 19);
            this.chkRandom.TabIndex = 3;
            this.chkRandom.Text = "Random Size";
            this.chkRandom.UseVisualStyleBackColor = true;
            // 
            // btnRemoveControl
            // 
            this.btnRemoveControl.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
            this.btnRemoveControl.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(64)))), ((int)(((byte)(0)))));
            this.btnRemoveControl.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(64)))), ((int)(((byte)(0)))));
            this.btnRemoveControl.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.btnRemoveControl.ForeColor = System.Drawing.Color.White;
            this.btnRemoveControl.Location = new System.Drawing.Point(136, 11);
            this.btnRemoveControl.Name = "btnRemoveControl";
            this.btnRemoveControl.Size = new System.Drawing.Size(119, 34);
            this.btnRemoveControl.TabIndex = 2;
            this.btnRemoveControl.Text = "Remove Control";
            this.btnRemoveControl.UseVisualStyleBackColor = false;
            this.btnRemoveControl.Click += new System.EventHandler(this.btnRemoveControl_Click);
            // 
            // btnAddControl
            // 
            this.btnAddControl.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
            this.btnAddControl.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(64)))), ((int)(((byte)(0)))));
            this.btnAddControl.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(64)))), ((int)(((byte)(0)))));
            this.btnAddControl.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.btnAddControl.ForeColor = System.Drawing.Color.White;
            this.btnAddControl.Location = new System.Drawing.Point(11, 11);
            this.btnAddControl.Name = "btnAddControl";
            this.btnAddControl.Size = new System.Drawing.Size(119, 34);
            this.btnAddControl.TabIndex = 0;
            this.btnAddControl.Text = "Add Control";
            this.btnAddControl.UseVisualStyleBackColor = false;
            this.btnAddControl.Click += new System.EventHandler(this.btnAddControl_Click);
            // 
            // panBackground
            // 
            this.panBackground.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.panBackground.AutoScroll = true;
            this.panBackground.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
            this.panBackground.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
            this.panBackground.Controls.Add(this.tlp1);
            this.panBackground.Location = new System.Drawing.Point(0, 0);
            this.panBackground.Name = "panBackground";
            this.panBackground.Size = new System.Drawing.Size(552, 360);
            this.panBackground.TabIndex = 3;
            // 
            // tlp1
            // 
            this.tlp1.AutoSize = true;
            this.tlp1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
            this.tlp1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
            this.tlp1.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Single;
            this.tlp1.ColumnCount = 1;
            this.tlp1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
            this.tlp1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
            this.tlp1.Dock = System.Windows.Forms.DockStyle.Top;
            this.tlp1.Location = new System.Drawing.Point(0, 0);
            this.tlp1.Name = "tlp1";
            this.tlp1.RowCount = 1;
            this.tlp1.RowStyles.Add(new System.Windows.Forms.RowStyle());
            this.tlp1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 1F));
            this.tlp1.Size = new System.Drawing.Size(552, 2);
            this.tlp1.TabIndex = 4;
            // 
            // frmTLPTest1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
            this.ClientSize = new System.Drawing.Size(552, 414);
            this.Controls.Add(this.panBackground);
            this.Controls.Add(this.panToolbar);
            this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.Name = "frmTLPTest1";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "frmTLPTest1";
            this.Load += new System.EventHandler(this.SOfrmTest1_Load);
            this.panToolbar.ResumeLayout(false);
            this.panToolbar.PerformLayout();
            this.panBackground.ResumeLayout(false);
            this.panBackground.PerformLayout();
            this.ResumeLayout(false);
        }
    
        private System.Windows.Forms.Panel panToolbar;
        private System.Windows.Forms.Button btnAddControl;
        private System.Windows.Forms.Button btnRemoveControl;
        private System.Windows.Forms.CheckBox chkRandom;
        private System.Windows.Forms.Panel panBackground;
        private System.Windows.Forms.TableLayoutPanel tlp1;
        private System.Windows.Forms.Button btnRemoveRow;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多