Walczyłem z tym od jakiegoś czasu i odkryłem, że wiele innych osób ma również problemy z TableLayoutPanel (.net 2.0 Winforms).
Problem
Usiłuję wziąć „pusty” tablelayoutpanel, który ma zdefiniowane 10 kolumn, a następnie programowo dodać wiersze kontrolek w czasie wykonywania (tj. Po jednej kontrolce na komórkę).
Można by pomyśleć, że powinno to być tak proste, jak
myTableLayoutPanel.Controls.Add(myControl, 0 /* Column Index */, 0 /* Row index */);
Ale to (dla mnie) nie dodaje wierszy. Więc może dodanie stylu wierszowego
myTableLayoutPanel.RowStyles.Clear();
myTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 30F));
Ale to też nie działa. Przekopałem się i odkryłem, że myTableLayoutPanel.RowCount
użycie zmienia się od czasu projektowania do czasu wykonywania, dlatego myTableLayoutPanel.RowCount++;
tak naprawdę nie dodaje to kolejnego wiersza, nawet przed / po dodaniu dla niego wpisu RowStyle!
Innym powiązanym problemem, z którym się spotykam, jest to, że kontrolki zostaną dodane do ekranu, ale wszystkie są po prostu renderowane w punkcie 0,0 TableLayoutPanel, a ponadto nie są nawet ograniczone tak, aby znajdowały się w granicach komórki, które powinny być wyświetlane w ramach (tj. z Dock = DockStyle.Fill nadal wydają się zbyt duże / małe).
Czy ktoś ma działający przykład dodawania wierszy i kontrolek w czasie wykonywania?
Odpowiedzi:
Właśnie to zrobiłem w zeszłym tygodniu. Ustaw
GrowStyle
naTableLayoutPanel
celuAddRows
lubAddColumns
, następnie Twój kod powinien działać:// Adds "myControl" to the first column of each row myTableLayoutPanel.Controls.Add(myControl1, 0 /* Column Index */, 0 /* Row index */); myTableLayoutPanel.Controls.Add(myControl2, 0 /* Column Index */, 1 /* Row index */); myTableLayoutPanel.Controls.Add(myControl3, 0 /* Column Index */, 2 /* Row index */);
Oto działający kod, który wydaje się podobny do tego, co robisz:
private Int32 tlpRowCount = 0; private void BindAddress() { Addlabel(Addresses.Street); if (!String.IsNullOrEmpty(Addresses.Street2)) { Addlabel(Addresses.Street2); } Addlabel(Addresses.CityStateZip); if (!String.IsNullOrEmpty(Account.Country)) { Addlabel(Address.Country); } Addlabel(String.Empty); // Notice the empty label... } private void Addlabel(String text) { label = new Label(); label.Dock = DockStyle.Fill; label.Text = text; label.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; tlpAddress.Controls.Add(label, 1, tlpRowCount); tlpRowCount++; }
TableLayoutPanel
Zawsze daje mi pasuje rozmiarem. W powyższym przykładzie wypełniam kartę adresową, która może się zwiększyć lub zmniejszyć w zależności od konta z drugą linią adresu lub kraju. Ponieważ ostatni wiersz lub kolumna panelu układu tabeli się rozciągnie, wrzucam tam pustą etykietę, aby wymusić nowy pusty wiersz, a następnie wszystko ładnie się układa.Oto kod projektanta, dzięki czemu możesz zobaczyć tabelę, od której zaczynam:
// // tlpAddress // this.tlpAddress.AutoSize = true; this.tlpAddress.BackColor = System.Drawing.Color.Transparent; this.tlpAddress.ColumnCount = 2; this.tlpAddress.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 25F)); this.tlpAddress.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tlpAddress.Controls.Add(this.pictureBox1, 0, 0); this.tlpAddress.Dock = System.Windows.Forms.DockStyle.Fill; this.tlpAddress.Location = new System.Drawing.Point(0, 0); this.tlpAddress.Name = "tlpAddress"; this.tlpAddress.Padding = new System.Windows.Forms.Padding(3); this.tlpAddress.RowCount = 2; this.tlpAddress.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tlpAddress.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tlpAddress.Size = new System.Drawing.Size(220, 95); this.tlpAddress.TabIndex = 0;
źródło
To dziwny projekt, ale
TableLayoutPanel.RowCount
właściwość nie odzwierciedla liczbyRowStyles
kolekcji, podobnie jak w przypadkuColumnCount
właściwości iColumnStyles
kolekcji.W moim kodzie znalazłem potrzebę ręcznej aktualizacji
RowCount
/ColumnCount
po wprowadzeniu zmian wRowStyles
/ColumnStyles
.Oto przykład kodu, którego użyłem:
/// <summary> /// Add a new row to our grid. /// </summary> /// The row should autosize to match whatever is placed within. /// <returns>Index of new row.</returns> public int AddAutoSizeRow() { Panel.RowStyles.Add(new RowStyle(SizeType.AutoSize)); Panel.RowCount = Panel.RowStyles.Count; mCurrentRow = Panel.RowCount - 1; return mCurrentRow; }
Inne przemyślenia
Nigdy nie robiłem,
DockStyle.Fill
aby kontrolka wypełniała komórkę w siatce; Zrobiłem to, ustawiającAnchors
właściwość kontrolki.Jeśli dodajesz wiele kontrolek, upewnij się, że wywołujesz
SuspendLayout
iResumeLayout
omijasz proces, w przeciwnym razie wszystko będzie działać wolno, gdy cały formularz zostanie ponownie umieszczony po dodaniu każdej kontrolki.źródło
Oto mój kod dodawania nowego wiersza do dwukolumnowej TableLayoutColumn:
private void AddRow(Control label, Control value) { int rowIndex = AddTableRow(); detailTable.Controls.Add(label, LabelColumnIndex, rowIndex); if (value != null) { detailTable.Controls.Add(value, ValueColumnIndex, rowIndex); } } private int AddTableRow() { int index = detailTable.RowCount++; RowStyle style = new RowStyle(SizeType.AutoSize); detailTable.RowStyles.Add(style); return index; }
Kontrolka etykiety znajduje się w lewej kolumnie, a kontrolka wartości w prawej kolumnie. Kontrolki są zazwyczaj typu Label i mają właściwość AutoSize ustawioną na true.
Nie sądzę, żeby to miało zbyt duże znaczenie, ale dla odniesienia, oto kod projektanta, który konfiguruje detailTable:
this.detailTable.ColumnCount = 2; this.detailTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.detailTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.detailTable.Dock = System.Windows.Forms.DockStyle.Fill; this.detailTable.Location = new System.Drawing.Point(0, 0); this.detailTable.Name = "detailTable"; this.detailTable.RowCount = 1; this.detailTable.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.detailTable.Size = new System.Drawing.Size(266, 436); this.detailTable.TabIndex = 0;
To wszystko działa dobrze. Należy pamiętać, że wydaje się, że istnieją pewne problemy z usuwaniem formantów z TableLayoutPanel dynamicznie przy użyciu właściwości Controls (przynajmniej w niektórych wersjach struktury). Jeśli chcesz usunąć kontrolki, sugeruję pozbycie się całego TableLayoutPanel i utworzenie nowego.
źródło
Utwórz panel układu tabeli z dwiema kolumnami w formularzu i nazwij go
tlpFields
.Następnie po prostu dodaj nową kontrolkę do panelu układu tabeli (w tym przypadku dodałem 5 etykiet w kolumnie-1 i 5 pól tekstowych w kolumnie-2).
tlpFields.RowStyles.Clear(); //first you must clear rowStyles for (int ii = 0; ii < 5; ii++) { Label l1= new Label(); TextBox t1 = new TextBox(); l1.Text = "field : "; tlpFields.Controls.Add(l1, 0, ii); // add label in column0 tlpFields.Controls.Add(t1, 1, ii); // add textbox in column1 tlpFields.RowStyles.Add(new RowStyle(SizeType.Absolute,30)); // 30 is the rows space }
Na koniec uruchom kod.
źródło
Właśnie przejrzałem swój kod. W jednej aplikacji po prostu dodaję kontrolki, ale bez określania indeksu, a po zakończeniu po prostu przechodzę przez style wierszy i ustawiam typ rozmiaru na AutoSize. Więc samo dodanie ich bez określania indeksów wydaje się dodawać wiersze zgodnie z przeznaczeniem (pod warunkiem, że GrowStyle jest ustawiony na AddRows).
W innej aplikacji wyczyszczam kontrolki i ustawiam właściwość RowCount na wymaganą wartość. Nie powoduje to dodania RowStyles. Następnie dodaję moje kontrolki, tym razem określając indeksy, i dodaję nowy RowStyle (
RowStyles.Add(new RowStyle(...)
) i to również działa.Więc wybierz jedną z tych metod, obie działają. Pamiętam bóle głowy spowodowane przez panel układu stołu.
źródło
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim dt As New DataTable Dim dc As DataColumn dc = New DataColumn("Question", System.Type.GetType("System.String")) dt.Columns.Add(dc) dc = New DataColumn("Ans1", System.Type.GetType("System.String")) dt.Columns.Add(dc) dc = New DataColumn("Ans2", System.Type.GetType("System.String")) dt.Columns.Add(dc) dc = New DataColumn("Ans3", System.Type.GetType("System.String")) dt.Columns.Add(dc) dc = New DataColumn("Ans4", System.Type.GetType("System.String")) dt.Columns.Add(dc) dc = New DataColumn("AnsType", System.Type.GetType("System.String")) dt.Columns.Add(dc) Dim Dr As DataRow Dr = dt.NewRow Dr("Question") = "What is Your Name" Dr("Ans1") = "Ravi" Dr("Ans2") = "Mohan" Dr("Ans3") = "Sohan" Dr("Ans4") = "Gopal" Dr("AnsType") = "Multi" dt.Rows.Add(Dr) Dr = dt.NewRow Dr("Question") = "What is your father Name" Dr("Ans1") = "Ravi22" Dr("Ans2") = "Mohan2" Dr("Ans3") = "Sohan2" Dr("Ans4") = "Gopal2" Dr("AnsType") = "Multi" dt.Rows.Add(Dr) Panel1.GrowStyle = TableLayoutPanelGrowStyle.AddRows Panel1.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single Panel1.BackColor = Color.Azure Panel1.RowStyles.Insert(0, New RowStyle(SizeType.Absolute, 50)) Dim i As Integer = 0 For Each dri As DataRow In dt.Rows Dim lab As New Label() lab.Text = dri("Question") lab.AutoSize = True Panel1.Controls.Add(lab, 0, i) Dim Ans1 As CheckBox Ans1 = New CheckBox() Ans1.Text = dri("Ans1") Panel1.Controls.Add(Ans1, 1, i) Dim Ans2 As RadioButton Ans2 = New RadioButton() Ans2.Text = dri("Ans2") Panel1.Controls.Add(Ans2, 2, i) i = i + 1 'Panel1.Controls.Add(Pan) Next
źródło
Działa to doskonale w przypadku dodawania wierszy i kontrolek w TableLayoutPanel.
Zdefiniuj pusty panel Tablelayoutpanel z 3 kolumnami na stronie projektu
Dim TableLayoutPanel3 As New TableLayoutPanel() TableLayoutPanel3.Name = "TableLayoutPanel3" TableLayoutPanel3.Location = New System.Drawing.Point(32, 287) TableLayoutPanel3.AutoSize = True TableLayoutPanel3.Size = New System.Drawing.Size(620, 20) TableLayoutPanel3.ColumnCount = 3 TableLayoutPanel3.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single TableLayoutPanel3.BackColor = System.Drawing.Color.Transparent TableLayoutPanel3.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 26.34146!)) TableLayoutPanel3.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 73.65854!)) TableLayoutPanel3.ColumnStyles.Add(New ColumnStyle(SizeType.Absolute, 85.0!)) Controls.Add(TableLayoutPanel3)
Utwórz przycisk btnAddRow, aby dodawać wiersze po każdym kliknięciu
Private Sub btnAddRow_Click(sender As System.Object, e As System.EventArgs) Handles btnAddRow.Click TableLayoutPanel3.GrowStyle = TableLayoutPanelGrowStyle.AddRows TableLayoutPanel3.RowStyles.Add(New RowStyle(SizeType.Absolute, 20)) TableLayoutPanel3.SuspendLayout() TableLayoutPanel3.RowCount += 1 Dim tb1 As New TextBox() Dim tb2 As New TextBox() Dim tb3 As New TextBox() TableLayoutPanel3.Controls.Add(tb1 , 0, TableLayoutPanel3.RowCount - 1) TableLayoutPanel3.Controls.Add(tb2, 1, TableLayoutPanel3.RowCount - 1) TableLayoutPanel3.Controls.Add(tb3, 2, TableLayoutPanel3.RowCount - 1) TableLayoutPanel3.ResumeLayout() tb1.Focus() End Sub
źródło
Właśnie miałem powiązany problem (i tak znalazłem ten wątek), w którym moje dynamicznie dodane style wierszy i kolumn nie działały. Zwykle traktuję SuspendLayout () / ResumeLayout () jako optymalizacje, ale w tym przypadku zawijanie w nie mojego kodu sprawiło, że wiersze i kolumny zachowywały się poprawnie.
źródło