Winforms TableLayoutPanel adicionando linhas de maneira programática

85

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.RowCountuso 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?

Cinza
fonte
Adicionar um RowStyle realmente aumentará o RowStyles.Count ()
Eduardo Hernández

Respostas:

75

Eu só fiz isso na semana passada. Defina o GrowStyleno TableLayoutPanelpara AddRowsou AddColumns, 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 TableLayoutPanelsempre 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;
Billy Coover
fonte
2
Exemplo perfeito e simples.
RandomInsano
2
Obrigado pela ideia de uma linha de espaço reservado vazia! Resolvido meus problemas de dimensionamento.
JNadal
30

É um design estranho, mas a TableLayoutPanel.RowCountpropriedade não reflete a contagem da RowStylescoleção e da mesma forma para a ColumnCountpropriedade e a ColumnStylescoleção.

O que descobri que precisava em meu código era atualizar manualmente RowCount/ ColumnCountdepois de fazer alterações em RowStyles/ 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.Fillpara fazer um controle preencher uma célula no Grid; Eu fiz isso definindo a Anchorspropriedade do controle.

  • Se você estiver adicionando muitos controles, certifique-se de chamar SuspendLayoute ResumeLayoutao 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.

Bevan
fonte
2
Se for útil para qualquer pessoa, no meu caso, tive que chamar tableLayoutPanel1.ColumnStyles.Clear (); quando o formulário está carregando.
John
17

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.

Cory McCarty
fonte
Isso foi muito útil. Descobri que o atributo DockStyle.Fill era essencial. Além disso, é surpreendentemente fácil cometer erros na contagem! Além disso, observe os tamanhos de coluna e linha definidos com estilos. Descobri que quando o RowStyle foi definido como AutoSize, algumas variações não intencionais nas configurações de TextAlign (entre Top, Middle e Bottom) fizeram parecer que a tabela estava gerando linhas extras de alguma forma estranha, mas não era o caso. A coisa funciona muito bem depois de descobrir, mas foi doloroso chegar lá!
Jan Hettich
7

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.

Ali Motamedi
fonte
como você está acessando tlpfields? Eu criei tablelayoutpanel e seu nome é tabkelayout, mas não consigo acessá-lo.
Muneem Habib
@MuneemHabib vá para tabkelayout properties e altere os modificadores de privado para público
RookieCoder
4

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.

OregonGhost
fonte
Vou dar uma chance a esses pra ver se ele se comporta!
Ash
0
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
Sujeet
fonte
A pergunta é sobre TableLayoutPanel, este post é sobre DataTable. A postagem é apenas um código. Não tem nenhum texto que descreva qual pode ser o ponto. Sem comentários no código também. Então, -1.
Nick Alexeev
0

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
EIV
fonte
0

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.

O começo da sabedoria
fonte