c# - ejemplos - Winforms TableLayoutPanel que agrega filas programáticamente
table layout panel c# dynamic (8)
He estado luchando con esto por un tiempo, y he descubierto que otras personas también tienen problemas con el TableLayoutPanel (.NET 2.0 Winforms).
Problema
Estoy intentando tomar un panel de panel de tareas ''en blanco'', que tiene 10 columnas definidas, luego, en tiempo de ejecución, programáticamente agregar filas de controles (es decir, un control por celda).
Uno 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. Así que tal vez agregar un estilo de fila
myTableLayoutPanel.RowStyles.Clear();
myTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 30F));
Pero eso tampoco funciona. He buscado y descubierto que el uso de myTableLayoutPanel.RowCount
cambia del tiempo de diseño al tiempo de ejecución, por lo tanto, haciendo myTableLayoutPanel.RowCount++;
en realidad no agrega otra fila, ¡ni siquiera antes / después de agregar una entrada RowStyle para ella!
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 del TableLayoutPanel, adicionalmente ni siquiera están limitados a estar dentro de los límites de la Celda que se supone que son visualizados dentro (es decir, con Dock = DockStyle.Fill, siguen apareciendo demasiado grandes / pequeños).
¿Alguien tiene un ejemplo funcional de agregar filas y controles en tiempo de ejecución?
Acabo de hacer esto la semana pasada. Establezca GrowStyle
en TableLayoutPanel
en AddRows
o AddColumns
, luego su 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++;
}
El TableLayoutPanel
siempre me da ajustes con el tamaño. En mi ejemplo anterior, estoy archivando una tarjeta de dirección que puede crecer o reducirse según la cuenta que 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 alargará, tiro la etiqueta vacía para forzar una nueva fila vacía, y luego todo se alinea muy bien.
Aquí está el código del diseñador para que pueda ver la tabla con la que empiezo:
//
// 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;
Acabo de mirar mi código. En una aplicación, simplemente agregué los controles, pero sin especificar el índice, y cuando termine, simplemente recorro los estilos de fila y configuro el tamaño de tamaño en AutoSize. Entonces, simplemente agregarlos sin especificar los índices parece agregar las filas como se pretende (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 los 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 diseño de la mesa.
Acabo de tener un problema relacionado (que es cómo encontré este hilo), donde los estilos de columna y columna agregados dinámicamente no estaban teniendo efecto. Normalmente considero a SuspendLayout () / ResumeLayout () como optimizaciones, pero en este caso, al ajustar mi código en ellas, las filas y columnas se comportan correctamente.
Aquí está mi código para agregar una nueva fila a 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 generalmente son de tipo Label y tienen su propiedad AutoSize establecida en verdadero.
No creo que importe demasiado, pero para referencia, aquí está el código de 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 los controles, le sugiero que elimine todo el TableLayoutPanel y cree uno nuevo.
Cree un panel de diseño de tabla con dos columnas en su formulario y tlpFields
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, ejecuta el código.
Es un diseño extraño, pero la propiedad TableLayoutPanel.RowCount
no refleja el recuento de la colección RowStyles
, y de manera similar para la propiedad ColumnCount
y la colección ColumnStyles
.
Lo que he encontrado que necesitaba en mi código era actualizar RowCount
/ ColumnCount
manualmente después de hacer cambios a 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.Fill
para hacer un control de llenar una celda en la Grilla; Lo he hecho estableciendo la propiedadAnchors
del control.Si está agregando muchos controles, asegúrese de llamar a
SuspendLayout
yResumeLayout
todo el proceso, de lo contrario las cosas se ejecutarán lentamente ya que todo el formulario se relaizará después de agregar cada control.
Esto funciona perfectamente para agregar filas y controles en TableLayoutPanel.
Defina un panel de Tablelayout 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
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