Eu tenho lutado com isso por um tempo e descobri que várias outras pessoas também lutam com o TableLayoutPanel (.net 2.0 Winforms).
Problema
Estou tentando pegar um tablelayoutpanel 'em branco', que tem 10 colunas definidas e, em tempo de execução, adicionar linhas de controles de forma programática (ou seja, um controle por célula).
Alguém pode ter pensado que deveria ser tão simples quanto
myTableLayoutPanel.Controls.Add(myControl, 0 /* Column Index */, 0 /* Row index */);
Mas isso (para mim) não adiciona as linhas. Então, talvez adicionando em uma linha estilo
myTableLayoutPanel.RowStyles.Clear();
myTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 30F));
Mas isso também não funciona. Eu pesquisei e descobri que o myTableLayoutPanel.RowCount
uso muda do tempo de design para o tempo de execução, portanto myTableLayoutPanel.RowCount++;
, não adiciona outra linha, nem mesmo antes / depois de adicionar uma entrada RowStyle para ela!
Outro problema relacionado que estou encontrando é que os controles serão adicionados à exibição, mas todos eles simplesmente são renderizados no ponto 0,0 do TableLayoutPanel, além disso, eles não são nem mesmo restritos a estar dentro dos limites da célula que deveriam estar exibidos dentro (ou seja, com Dock = DockStyle.Fill eles ainda aparecem muito grandes / pequenos).
Alguém tem um exemplo prático de adição de linhas e controles em tempo de execução?
Respostas:
Eu só fiz isso na semana passada. Defina o
GrowStyle
noTableLayoutPanel
paraAddRows
ouAddColumns
, então o seu código deve funcionar:// 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 */);
Aqui está um código de trabalho que parece semelhante ao que você está fazendo:
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++; }
O
TableLayoutPanel
sempre me dá se encaixa com o tamanho. No meu exemplo acima, estou preenchendo um cartão de endereço que pode aumentar ou diminuir, dependendo da conta ter uma linha de endereço dois ou um país. Como a última linha, ou coluna, do painel de layout da tabela será esticada, coloco o rótulo vazio ali para forçar uma nova linha vazia, então tudo se alinha perfeitamente.Aqui está o código do designer para que você possa ver a tabela com a qual começo:
// // 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;
fonte
É um design estranho, mas a
TableLayoutPanel.RowCount
propriedade não reflete a contagem daRowStyles
coleção e da mesma forma para aColumnCount
propriedade e aColumnStyles
coleção.O que descobri que precisava em meu código era atualizar manualmente
RowCount
/ColumnCount
depois de fazer alterações emRowStyles
/ColumnStyles
.Aqui está um exemplo de código que usei:
/// <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; }
Outros pensamentos
Eu nunca usei
DockStyle.Fill
para fazer um controle preencher uma célula no Grid; Eu fiz isso definindo aAnchors
propriedade do controle.Se você estiver adicionando muitos controles, certifique-se de chamar
SuspendLayout
eResumeLayout
ao redor do processo, caso contrário, as coisas ficarão lentas, pois todo o formulário será relançado após cada controle ser adicionado.fonte
Este é meu código para adicionar uma nova linha a uma TableLayoutColumn de duas colunas:
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; }
O controle de rótulo vai para a coluna esquerda e o controle de valor vai para a coluna direita. Os controles são geralmente do tipo Label e têm sua propriedade AutoSize definida como true.
Não acho que isso importe muito, mas para referência, aqui está o código do designer que configura a tabela de detalhes:
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;
Tudo isso funciona muito bem. Você deve estar ciente de que parece haver alguns problemas com o descarte de controles de um TableLayoutPanel dinamicamente usando a propriedade Controls (pelo menos em algumas versões da estrutura). Se você precisar remover controles, sugiro descartar todo o TableLayoutPanel e criar um novo.
fonte
Crie um painel de layout de tabela com duas colunas em seu formulário e nomeie-o
tlpFields
.Em seguida, basta adicionar um novo controle ao painel de layout da tabela (neste caso, adicionei 5 rótulos na coluna 1 e 5 caixas de texto na coluna 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 }
Finalmente, execute o código.
fonte
Acabei de verificar meu código. Em um aplicativo, eu apenas adiciono os controles, mas sem especificar o índice e, quando pronto, simplesmente faço um loop pelos estilos de linha e defino o tipo de tamanho como AutoSize. Portanto, apenas adicioná-los sem especificar os índices parece adicionar as linhas conforme pretendido (desde que GrowStyle seja definido como AddRows).
Em outro aplicativo, eu limpo os controles e defino a propriedade RowCount com o valor necessário. Isso não adiciona o RowStyles. Então adiciono meus controles, desta vez especificando os índices, e adiciono um novo RowStyle (
RowStyles.Add(new RowStyle(...)
) e isso também funciona.Então, escolha um desses métodos, ambos funcionam. Lembro-me das dores de cabeça que o painel de layout da mesa me causou.
fonte
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
fonte
Isso funciona perfeitamente para adicionar linhas e controles em um TableLayoutPanel.
Defina um Tablelayoutpanel em branco com 3 colunas na página de design
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)
Crie um botão btnAddRow para adicionar linhas a cada clique
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
fonte
Acabei de ter um problema relacionado (que foi como encontrei este tópico), onde meus estilos de linha e coluna adicionados dinamicamente não estavam tendo efeito. Eu geralmente considero SuspendLayout () / ResumeLayout () como otimizações, mas, neste caso, envolver meu código nelas fez com que as linhas e colunas se comportassem corretamente.
fonte