删除TableLayoutPanel中的行会产生布局问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了删除TableLayoutPanel中的行会产生布局问题相关的知识,希望对你有一定的参考价值。
我有一个有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--;
}
问题是当我删除一行时,表底部会留下一个大空间:TableLayoutPanel不会回收panel1
的大小。
基于评论和此答案中描述的布局的解决方案,之前发布: Center multiple rows of controls in a FlowLayoutPanel
描述: (本帖底部提供的测试表的完整代码)
- 创建一个新表单(此处名为
frmTLPTest1
) - 添加两个面板。一个用于托管一些按钮,另一个用于TableLayoutPanel的Container。
- 将Container面板设置为
AutoScroll = true
,AutoSizeMode = AutoSizeMode.GrowAndShrink
,设置所有锚点(左,上,右,下) - 在Container面板中,删除一个新的TableLayoutPanel:将其设置为
AutoSize = true
,AutoSizeMode = AutoSizeMode.GrowAndShrink
,Dock = DockStyle.Top
- 从TableLayoutPanel中删除所有行和列,除了其中一个(不能全部删除)。将两者的尺寸设置为
AutoSize
。
重要说明(也在相关答案中报告):
在Form构造函数中,删除了其中一个RowStyles。这很重要:TLP将保留2个RowStyles。一个适用于现有的Row;第二种样式将应用于您添加的第一行:仅应用于第一行,而不应用于其他行。如果未删除此样式,则会影响布局。
用于从TableLayoutPanel添加行到/删除行的核心方法,使用FlowLayoutPanel作为TLP行内容,并最终也可以用作其他控件的容器。
TlpAddRow(TableLayoutPanel tlp, bool addRowCount)
方法:
将新的FlowLayoutPanel添加到指定的TableLayoutPanel的Cell,并在请求时添加新的Row。
由于Designer不允许删除所有行,因此第一行(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。要删除的行可以从用作行容器的Control(此处为FlowLayoutPanel,但它可以是Panel,另一个TableLayoutPanel或其他类型的Container控件)派生。 也可以通过直接指定Row索引来删除Row。
private void TLPRemoveRow(TableLayoutPanel tlp, Control control)
{
int ctlRow = this.tlp1.GetRow(control);
TLPRemoveRow(tlp, ctlRow);
}
private void TLPRemoveRow(TableLayoutPanel tlp, int row)
{
if (row < this.tlp1.RowCount - 1) {
for (int i = row; i < this.tlp1.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();
this.tlp1.RowStyles.RemoveAt(1);
}
private void SOfrmTest1_Load(object sender, EventArgs e)
{
TlpAddRow(this.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 (this.chkRandom.Checked)
size = sizes[rnd.Next(sizes.Length)];
PictureBox 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 (this.tlp1.RowCount == 0) TlpAddRow(this.tlp1, true);
var ctl = this.tlp1.GetControlFromPosition(0, this.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 >= this.tlp1.Width) {
ctl = TlpAddRow(this.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(this.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(this.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 = this.tlp1.GetRow(control);
TLPRemoveRow(tlp, ctlRow);
}
private void TLPRemoveRow(TableLayoutPanel tlp, int row)
{
if (row < this.tlp1.RowCount - 1) {
for (int i = row; i < this.tlp1.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.Drawi以上是关于删除TableLayoutPanel中的行会产生布局问题的主要内容,如果未能解决你的问题,请参考以下文章
从 UITableView 中删除行会更改存储在其他行中的信息