这是一个重现您所描述的行为的示例。
它使用托管多个 FlowLayoutPanel 的 TableLayoutPanel。
一个重要的细节是子 FlowLayoutPanel 的锚定:它们需要锚定到上下:这会导致面板位于 TableLayoutPanel 行的中心。
请注意,在 Form 构造函数中,其中之一RowStyles
已移除。这一点也非常重要:TLP
(这是一个非常古怪的家伙),即使你只有一行(或一列,同样的事情),也会保留 2RowStyles
。第二种样式将应用于您添加的第一行;只针对第一个,而不是其他:这可能会搞乱布局。
另一个异常是,它没有提供删除行的方法,所以我做了一个。它功能齐全,但很简陋,需要扩展,包括进一步验证。
请参阅有关当前功能的图形示例。如果您在实施其他方面需要帮助,请发表评论。
要构建此控件,请将以下控件添加到表单(此处称为FLPTest1
):
- 添加一个Panel,设置
Dock.Bottom
。右键单击并SendToBack()
,
- Add a
TableLayoutPanel
(here, called tlp1
), set:
-
AutoScroll = true
, AutoSize = true
,
-
AutoSizeMode = GrowAndShrink
, Dock.Fill
- 保留 1 列,设置为 AutoSize,保留 1 行,设置为 AutoSize
- Add a
FlowLayoutPanel
(here, called flp1
), positioned inside the TableLayoutPanel
. It's not actually necessary, just for this sample code
- 将其锚点设置为
Top, Bottom <=
这是!important
,如果没有它,布局将无法正常工作:它允许将FLP
在 - 的里面TLP
Row,
-
AutoSize = true
, AutoSizeMode = GrowAndShrink
- 添加一个按钮(称为
btnAddControl
)
- 添加第二个按钮(称为
btnRemoveControl
)
- 添加一个复选框(称为
chkRandom
)
- 将代码粘贴到表单的代码文件中
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public partial class TLPTest1 : Form
{
public TLPTest1()
{
InitializeComponent();
tlp1.RowStyles.RemoveAt(1);
}
private void TLPTest1_Load(object sender, EventArgs e)
{
PictureBox pBox = new PictureBox() {
Anchor = AnchorStyles.None,
BackColor = Color.Orange,
MinimumSize = new Size(125, 125),
Size = new Size(125, 125),
};
flp1.Controls.Add(pBox);
tlp1.Controls.Add(flp1);
}
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;
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;
// Just for testing - use standard delegates instead of Lambdas in real code
pBox.MouseEnter += (s, evt) => { drawborder = true; pBox.Invalidate(); };
pBox.MouseLeave += (s, evt) => { drawborder = false; pBox.Invalidate(); };
pBox.MouseDown += (s, evt) => { selectedObject = pBox; pBox.Invalidate(); };
pBox.Paint += (s, evt) => { if (drawborder) {
ControlPaint.DrawBorder(evt.Graphics, pBox.ClientRectangle,
Color.White, ButtonBorderStyle.Solid);
}
};
var ctl = tlp1.GetControlFromPosition(0, tlp1.RowCount - 1);
int overallWith = ctl.Controls.OfType<Control>().Sum(c => c.Width + c.Margin.Left + c.Margin.Right);
overallWith += (ctl.Margin.Right + ctl.Margin.Left);
if ((overallWith + pBox.Size.Width + pBox.Margin.Left + pBox.Margin.Right) >= tlp1.Width) {
var flp = new FlowLayoutPanel() {
Anchor = AnchorStyles.Top | AnchorStyles.Bottom,
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink,
};
flp.Controls.Add(pBox);
tlp1.SuspendLayout();
tlp1.RowCount += 1;
tlp1.Controls.Add(flp, 0, tlp1.RowCount - 1);
tlp1.ResumeLayout(true);
}
else {
ctl.Controls.Add(pBox);
}
}
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 void TLPRemoveRow(TableLayoutPanel tlp, Control control)
{
int ctlPosition = tlp.GetRow(control);
if (ctlPosition < tlp.RowCount - 1) {
for (int i = ctlPosition; i < tlp.RowCount - 1; i++) {
tlp.SetRow(tlp.GetControlFromPosition(0, i + 1), i);
}
}
tlp.RowCount -= 1;
}
}