Winforms TableLayoutPanel agregando filas mediante programación

85

He estado luchando con esto por un tiempo, y descubrí que otras personas también luchan con TableLayoutPanel (.net 2.0 Winforms).

Problema

Estoy intentando tomar un panel de diseño de tabla 'en blanco', que tiene 10 columnas definidas, luego, en tiempo de ejecución, agrego filas de controles mediante programación (es decir, un control por celda).

Se podría haber pensado que debería ser tan simple como

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

Pero eso (para mí) no agrega las filas. Entonces tal vez agregando un estilo de fila

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

Pero eso tampoco funciona. Investigué y descubrí que el myTableLayoutPanel.RowCountuso cambia desde el tiempo de diseño hasta el tiempo de ejecución, por lo tanto, hacerlo myTableLayoutPanel.RowCount++;no agrega otra fila, ¡ni siquiera antes / después de agregar una entrada RowStyle!

Otro problema relacionado que estoy encontrando es que los controles se agregarán a la pantalla, pero todos simplemente se renderizan en el punto 0,0 de TableLayoutPanel, además, ni siquiera están restringidos a estar dentro de los límites de la celda que se supone que deben estar mostrados dentro (es decir, con Dock = DockStyle.Fill todavía parecen demasiado grandes / pequeños)

¿Alguien tiene un ejemplo práctico de agregar filas y controles en tiempo de ejecución?

Ceniza
fuente
Agregar un RowStyle en realidad aumentará RowStyles.Count ()
Eduardo Hernández

Respuestas:

75

Hice esto la semana pasada. Ajuste el GrowStyleen la TableLayoutPanelque AddRowso AddColumns, a continuación, el código debería 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 */);

Aquí hay un código de trabajo que parece similar a lo que está haciendo:

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

los TableLayoutPanel siempre me ajusta a la talla. En mi ejemplo anterior, estoy presentando una tarjeta de dirección que podría crecer o reducirse dependiendo de que la cuenta tenga una línea de dirección dos o un país. Debido a que la última fila, o columna, del panel de diseño de la tabla se estirará, coloco la etiqueta vacía allí para forzar una nueva fila vacía, luego todo se alinea bien.

Aquí está el código del diseñador para que pueda ver la tabla con la que comienzo:

        //
        // 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
fuente
2
Ejemplo perfecto y sencillo.
RandomInsano
2
¡Gracias por la idea de una fila de marcador de posición vacía! Resolví mis problemas de tamaño.
JNadal
30

Es un diseño extraño, pero la TableLayoutPanel.RowCountpropiedad no refleja el recuento de la RowStylescolección, y lo mismo ocurre con la ColumnCountpropiedad y la ColumnStylescolección.

Lo que encontré que necesitaba en mi código era actualizar manualmente RowCount/ ColumnCountdespués de realizar cambios en RowStyles/ ColumnStyles.

Aquí hay un ejemplo de código que he usado:

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

Otros pensamientos

  • Nunca he usado DockStyle.Fillpara hacer que un control llene una celda en la Grid; He hecho esto estableciendo la Anchorspropiedad del control.

  • Si está agregando muchos controles, asegúrese de llamar SuspendLayouty ResumeLayoutrodear el proceso; de lo contrario, las cosas se ejecutarán lentamente, ya que todo el formulario se volverá a publicar después de agregar cada control.

Bevan
fuente
2
Si es útil para alguien, en mi caso tuve que llamar a tableLayoutPanel1.ColumnStyles.Clear (); cuando se carga el formulario.
John
17

Aquí está mi código para agregar una nueva fila a una TableLayoutColumn de dos columnas:

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

El control de etiqueta va en la columna de la izquierda y el control de valor va en la columna de la derecha. Los controles son generalmente de tipo Label y tienen su propiedad AutoSize establecida en true.

No creo que importe demasiado, pero como referencia, aquí está el código del diseñador que configura 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;

Todo esto funciona bien. Debe tener en cuenta que parece haber algunos problemas con la eliminación de controles de un TableLayoutPanel dinámicamente utilizando la propiedad Controls (al menos en algunas versiones del marco). Si necesita eliminar controles, le sugiero que elimine todo el TableLayoutPanel y cree uno nuevo.

Cory McCarty
fuente
Esto fue muy útil. Descubrí que el atributo DockStyle.Fill era esencial. Además, ¡es sorprendentemente fácil cometer errores al contar! Además, tenga en cuenta los tamaños de columna y fila establecidos con estilos. Descubrí que cuando RowStyle se estableció en AutoSize, algunas variaciones involuntarias en la configuración de TextAlign (entre Top, Middle e Bottom) hacían que pareciera que la tabla estaba generando filas adicionales de alguna manera extraña, pero ese no era el caso. La cosa funciona bastante bien una vez que lo descubres, ¡pero fue doloroso llegar allí!
Jan Hettich
7

Cree un panel de diseño de tabla con dos columnas en su formulario y asígnele un nombre tlpFields.

Luego, simplemente agregue un nuevo control al panel de diseño de la tabla (en este caso agregué 5 etiquetas en la columna 1 y 5 cuadros de texto en la columna 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, ejecute el código.

Ali Motamedi
fuente
¿cómo accedes a tlpfields? He creado tablelayoutpanel y su nombre es tabkelayout pero no puedo acceder a esto.
Muneem Habib
@MuneemHabib vaya a las propiedades de tabkelayout y cambie los modificadores de privado a público
RookieCoder
4

Solo miré en mi código. En una aplicación, solo agrego los controles, pero sin especificar el índice, y cuando termino, simplemente recorro los estilos de fila y establezco el tipo de tamaño en AutoSize. Entonces, simplemente agregarlos sin especificar los índices parece agregar las filas según lo previsto (siempre que GrowStyle esté configurado en AddRows).

En otra aplicación, borro los controles y establezco la propiedad RowCount en el valor necesario. Esto no agrega RowStyles. Luego agrego mis controles, esta vez especificando los índices, y agrego un nuevo RowStyle ( RowStyles.Add(new RowStyle(...)) y esto también funciona.

Entonces, elija uno de estos métodos, ambos funcionan. Recuerdo los dolores de cabeza que me causó el panel de distribución de la mesa.

OregonGhost
fuente
¡Probaré estos para ver si se comportan bien!
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
fuente
La pregunta es sobre TableLayoutPanel, esta publicación es sobre DataTable. La publicación es solo de código. No tiene ningún texto que describa cuál podría ser el punto. Tampoco hay comentarios en el código. Entonces, -1.
Nick Alexeev
0

Esto funciona perfectamente para agregar filas y controles en un TableLayoutPanel.

Defina un panel de diseño de tabla en blanco con 3 columnas en la página de diseño

    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)

Cree un botón btnAddRow para agregar filas en cada 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
EIV
fuente
0

Acabo de tener un problema relacionado (que es cómo encontré este hilo), donde mis estilos de fila y columna agregados dinámicamente no estaban surtiendo efecto. Por lo general, considero SuspendLayout () / ResumeLayout () como optimizaciones, pero en este caso, envolver mi código en ellas hizo que las filas y columnas se comportaran correctamente.

El comienzo de la sabiduría
fuente