Pusatkan beberapa baris kontrol dalam FlowLayoutPanel
Saya mencoba membuat panel yang akan menjadi tuan rumah kontrol yang ditambahkan secara dinamis. Ada dua peringatan:
- Akan ada banyak kontrol, jadi panel harus membungkus elemen menjadi baris baru saat mencapai batas lebarnya dan menggulir secara vertikal.
- Kontrol dapat berubah ukuran, yang akan mengubah jumlah elemen
yang dapat ditampung dalam satu baris.
Saya telah melihat beberapa solusi yang diusulkan untuk memusatkan kontrol dinamis dalam Formulir dan menolaknya karena alasan berikut:
- TableLayoutPanel - masalah utama yang saya miliki dengan menggunakan ini adalah peristiwa ketika elemen tumbuh dan harus bergeser dari kisi 3-2 ke 2-4, karena TableLayoutPanel tampaknya tidak menangani hal itu dengan baik.
- AutoSize FlowLayoutPanel yang dapat tumbuh dan menyusut di dalam TableLayoutControl - masalah utama saya dengan solusi ini adalah solusi ini hanya memusatkan satu baris di dalam Formulir, setelah membungkus ke baris baru, elemen mulai sejajar ke sisi kanan. Saya kira saya dapat secara dinamis menambahkan FlowLayoutPanels baru ke baris baru dari TableLayoutControl, tetapi kemudian saya memiliki masalah yang sama seperti skenario pertama di mana saya perlu mendistribusikan ulang elemen secara manual di antara baris jika ukurannya bertambah / menyusut.
Saya ingin tahu apakah saya kehilangan beberapa fungsionalitas yang dapat membantu saya menangani acara tumbuh / menyusut tanpa membuat variasi TableLayoutPanel saya sendiri?
Edit:
Di bawah ini adalah draf fungsionalitas:
- A - Dua elemen berpusat di panel
- B - Elemen ketiga ditambahkan, ketiganya berada di tengah
- C - Elemen Keempat ditambahkan, dibungkus ke baris baru dan di tengah
- D - Elemen diperbesar, sekarang membungkus elemen kedua, di tengah
Jawaban
Berikut adalah contoh yang mereproduksi perilaku yang Anda jelaskan.
Itu menggunakan TableLayoutPanel yang menghosting beberapa FlowLayoutPanels.
Satu detail penting adalah penahan dari anak FlowLayoutPanels: mereka harus ditambatkan ke Atas-Bawah : ini menyebabkan panel diposisikan di tengah Baris TableLayoutPanel.
Perhatikan bahwa, dalam konstruktor Formulir, salah satu dari yang RowStylesdihapus. Ini juga sangat penting: the TLP(yang cukup eksentrik), meskipun Anda hanya memiliki satu Baris (atau satu Kolom, hal yang sama), akan menyimpan 2 RowStyles. Gaya kedua akan diterapkan ke Baris pertama yang Anda tambahkan; hanya untuk yang pertama, bukan yang lain: ini dapat mengacaukan tata letak.
Anomali lain, tidak menyediakan metode untuk menghapus Row, jadi saya telah membuatnya. Ini fungsional tetapi sederhana dan perlu diperpanjang, termasuk validasi lebih lanjut.
Lihat contoh grafik tentang fungsionalitas saat ini. Jika Anda membutuhkan bantuan dalam mengimplementasikan sesuatu yang lain, tinggalkan komentar.
Untuk membangun ini tambahkan kontrol berikut ke Formulir (di sini, disebut FLPTest1):
- Tambahkan satu Panel, atur
Dock.Bottom. Klik kanan danSendToBack(), - Tambahkan
TableLayoutPanel(di sini, disebuttlp1), setel:AutoScroll = true,AutoSize = true,AutoSizeMode = GrowAndShrink,Dock.Fill- Pertahankan 1 Kolom, setel ke UkuranOtomatis dan satu Baris, setel ke UkuranOtomatis
- Tambahkan
FlowLayoutPanel(di sini, disebutflp1), diposisikan di dalamTableLayoutPanel. Sebenarnya tidak perlu, hanya untuk kode contoh ini- Atur Anchor-nya ke
Top, Bottom <=ini!important, tata letak tidak akan berfungsi dengan benar tanpanya: ini memungkinkan untuk memusatkan bagianFLPdalamTLPRow, AutoSize = true,AutoSizeMode = GrowAndShrink
- Atur Anchor-nya ke
- Tambahkan Tombol (disebut
btnAddControl) - Tambahkan Tombol kedua (disebut
btnRemoveControl) - Tambahkan Kotak Centang (disebut
chkRandom) - Tempel kode di sini di dalam file kode Formulir
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public partial class TLPTest1 : Form
{
public TLPTest1()
{
InitializeComponent();
this.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),
};
this.flp1.Controls.Add(pBox);
this.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 (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) => { selectedObject = pBox; pBox.Invalidate(); };
pBox.Paint += (s, evt) => { if (drawborder) {
ControlPaint.DrawBorder(evt.Graphics, pBox.ClientRectangle,
Color.White, ButtonBorderStyle.Solid);
}
};
var ctl = this.tlp1.GetControlFromPosition(0, this.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) >= this.tlp1.Width)
{
var flp = new FlowLayoutPanel() {
Anchor = AnchorStyles.Top | AnchorStyles.Bottom,
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink,
};
flp.Controls.Add(pBox);
this.tlp1.SuspendLayout();
this.tlp1.RowCount += 1;
this.tlp1.Controls.Add(flp, 0, this.tlp1.RowCount - 1);
this.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(this.tlp1, parent);
parent.Dispose();
}
}
private void TLPRemoveRow(TableLayoutPanel tlp, Control control)
{
int ctlPosition = this.tlp1.GetRow(control);
if (ctlPosition < this.tlp1.RowCount - 1)
{
for (int i = ctlPosition; i < this.tlp1.RowCount - 1; i++)
{
tlp.SetRow(tlp.GetControlFromPosition(0, i + 1), i);
}
}
tlp.RowCount -= 1;
}
}