Winforms TableLayoutPanel aggiunta di righe a livello di codice


85

Ho combattuto con questo per un po 'e ho scoperto che molte altre persone hanno problemi anche con TableLayoutPanel (.net 2.0 Winforms).

Problema

Sto tentando di prendere un tablelayoutpanel "vuoto", che ha 10 colonne definite, quindi in fase di esecuzione aggiungere in modo programmatico righe di controlli (cioè un controllo per cella).

Si potrebbe pensare che dovrebbe essere semplice come

myTableLayoutPanel.Controls.Add(myControl, 0 /* Column Index */, 0 /* Row index */);

Ma questo (per me) non aggiunge le righe. Quindi forse aggiungendo uno stile di riga

myTableLayoutPanel.RowStyles.Clear();
myTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 30F));

Ma neanche questo funziona. Ho scavato un myTableLayoutPanel.RowCountpo ' e ho scoperto che l' utilizzo cambia dal tempo di progettazione al tempo di esecuzione, quindi fare in myTableLayoutPanel.RowCount++;realtà non aggiunge un'altra riga, nemmeno prima / dopo aver aggiunto una voce RowStyle per esso!

Un altro problema correlato che sto riscontrando è che i controlli verranno aggiunti al display, ma vengono semplicemente renderizzati tutti al punto 0,0 del TableLayoutPanel, inoltre non sono nemmeno vincolati a rientrare nei limiti della cella che dovrebbero essere visualizzati all'interno (cioè con Dock = DockStyle.Fill appaiono ancora troppo grandi / piccoli).

Qualcuno ha un esempio funzionante di aggiunta di righe e controlli in fase di esecuzione?


L'aggiunta di un RowStyle aumenterà effettivamente RowStyles.Count ()
Eduardo Hernández

Risposte:


75

L'ho appena fatto la scorsa settimana. Impostare il GrowStylesul TableLayoutPanelper AddRowso AddColumns, allora il codice dovrebbe funzionare:

// 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 */);

Ecco del codice funzionante che sembra simile a quello che stai facendo:

    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++;
    }

Il TableLayoutPaneldà sempre mi si adatta con la dimensione. Nel mio esempio sopra, sto archiviando una scheda di indirizzo che potrebbe crescere o ridursi a seconda che l'account abbia una riga dell'indirizzo due o un paese. Poiché l'ultima riga, o colonna, del pannello di layout della tabella si allungherà, inserisco l'etichetta vuota per forzare una nuova riga vuota, quindi tutto si allinea bene.

Ecco il codice del designer in modo da poter vedere la tabella con cui inizio:

        //
        // 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;

2
Grazie per l'idea di una riga segnaposto vuota! Risolto i miei problemi di dimensionamento.
JNadal

30

È un design strano, ma la TableLayoutPanel.RowCountproprietà non riflette il conteggio della RowStylesraccolta, e allo stesso modo per la ColumnCountproprietà e la ColumnStylesraccolta.

Quello che ho trovato di cui avevo bisogno nel mio codice era aggiornare manualmente RowCount/ ColumnCountdopo aver apportato modifiche a RowStyles/ ColumnStyles.

Ecco un esempio di codice che ho usato:

    /// <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;
    }

Altri pensieri

  • Non ho mai usato DockStyle.Fillper fare in modo che un controllo riempisse una cella nella griglia; L'ho fatto impostando la Anchorsproprietà del controllo.

  • Se stai aggiungendo molti controlli, assicurati di chiamare SuspendLayoute ResumeLayoutaggirare il processo, altrimenti le cose funzioneranno lentamente poiché l'intero modulo viene rilanciato dopo l'aggiunta di ogni controllo.


2
Se è utile per chiunque, nel mio caso ho dovuto chiamare tableLayoutPanel1.ColumnStyles.Clear (); quando il modulo viene caricato.
John

17

Ecco il mio codice per aggiungere una nuova riga a una TableLayoutColumn a due colonne:

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;
}

Il controllo dell'etichetta va nella colonna di sinistra e il controllo del valore va nella colonna di destra. I controlli sono generalmente di tipo Label e hanno la proprietà AutoSize impostata su true.

Non penso che sia importante, ma per riferimento, ecco il codice del designer che imposta 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;

Funziona tutto bene. È necessario essere consapevoli del fatto che sembrano esserci alcuni problemi con l'eliminazione dinamica dei controlli da un TableLayoutPanel utilizzando la proprietà Controls (almeno in alcune versioni del framework). Se è necessario rimuovere i controlli, suggerisco di eliminare l'intero TableLayoutPanel e crearne uno nuovo.


Questo è stato molto utile. Ho scoperto che l'attributo DockStyle.Fill era essenziale. Inoltre, è sorprendentemente facile commettere errori con il conteggio! Inoltre, nota le dimensioni delle colonne e delle righe impostate con gli stili. Ho scoperto che quando RowStyle era impostato su AutoSize, alcune variazioni involontarie nelle impostazioni TextAlign (tra Top, Middle e Bottom) facevano sembrare che la tabella stesse generando righe aggiuntive in qualche modo strano, ma non era così. La cosa funziona abbastanza bene una volta capito, ma è stato doloroso arrivarci!
Jan Hettich

7

Crea un pannello di layout tabella con due colonne nel modulo e assegnagli un nome tlpFields.

Quindi, aggiungi semplicemente un nuovo controllo al pannello del layout della tabella (in questo caso ho aggiunto 5 etichette nella colonna 1 e 5 caselle di testo nella colonna 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
}

Infine, esegui il codice.


come si accede a tlpfields? Ho creato tablelayoutpanel e il suo nome è tabkelayout ma non posso accedervi.
Muneem Habib

@MuneemHabib vai alle proprietà tabkelayout e cambia i modificatori da privato a pubblico
RookieCoder

4

Ho appena esaminato il mio codice. In un'applicazione, aggiungo solo i controlli, ma senza specificare l'indice e, al termine, scorro semplicemente gli stili di riga e imposto il tipo di dimensione su Dimensione automatica. Quindi semplicemente aggiungendoli senza specificare gli indici sembra aggiungere le righe come previsto (a condizione che GrowStyle sia impostato su AddRows).

In un'altra applicazione, deseleziono i controlli e imposto la proprietà RowCount sul valore necessario. Ciò non aggiunge RowStyles. Quindi aggiungo i miei controlli, questa volta specificando gli indici, e aggiungo un nuovo RowStyle ( RowStyles.Add(new RowStyle(...)) e anche questo funziona.

Quindi, scegli uno di questi metodi, funzionano entrambi. Ricordo i mal di testa che mi ha causato il pannello di layout del tavolo.


Proverò questi per vedere se si comportano bene!
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

La domanda riguarda TableLayoutPanel, questo post riguarda DataTable. Il post è solo codice. Non ha alcun testo che descriva quale potrebbe essere il punto. Nessun commento neanche nel codice. Quindi, -1.
Nick Alexeev

0

Funziona perfettamente per l'aggiunta di righe e controlli in un TableLayoutPanel.

Definisci un pannello Tablelayoutpanel vuoto con 3 colonne nella pagina di progettazione

    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)

Creare un pulsante btnAddRow per aggiungere righe a ogni clic

     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

0

Ho appena avuto un problema correlato (che è come ho trovato questo thread), in cui i miei stili di riga e colonna aggiunti dinamicamente non avevano effetto. Di solito considero SuspendLayout () / ResumeLayout () come ottimizzazioni, ma in questo caso, avvolgendo il mio codice in essi, le righe e le colonne si comportano correttamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.