Esta página puede contener texto traducido automáticamente.
Contenedor de tabla
Use contenedores Table para organizar sus datos más complejos. Las tablas desempeñan un papel crucial en los documentos PDF, mejorando su claridad y eficacia.
Las tablas proporcionan un formato estructurado para presentar sus datos. Permiten presentar detalles complejos de forma concisa y visualmente atractiva. En lugar de párrafos extensos, puede usar tablas para presentar hechos, cifras y tendencias de manera sucinta.
Una tabla bien diseñada mejora la legibilidad. Al alinear columnas y filas, crea una estructura que guía la vista del lector. Puede usar fondos, bordes y estilos de fuente para resaltar celdas o encabezados específicos.

Obtenga un contenedor de tabla llamando al método LayoutContainer.Table. Luego debe definir al menos una columna en el contenedor. En el caso más simple, puede rellenar todas las columnas y filas llamando varias veces al método Cell.
Continúe leyendo para saber cómo definir columnas y agregar un encabezado y/o pie a una tabla. El texto también describe el resto de las características del contenedor Table.
Este artículo forma parte de una serie sobre Layout API para la generación de PDF. Si es nuevo en la API, lea primero la sección Primeros pasos con Layout API.
Columnas y filas
Toda tabla debe definir al menos una columna. Use el método Table.Columns para definir columnas. El método acepta un delegado de tipo Action<TableColumnContainer>. En el código del delegado, agregue columnas a la tabla llamando a métodos del objeto proporcionado.
El método ConstantColumn agrega una columna con un ancho igual a un número exacto de puntos.
El método RelativeColumn agrega una columna con un ancho relativo. El método acepta el número de partes que debe ocupar la columna. El número total de partes es la suma de todos los números de todas las llamadas a RelativeColumn en esta tabla. En su mayor parte, este método funciona igual que RelativeItem del contenedor de fila. Consulte el enlace para obtener una explicación detallada.
No es necesario definir las filas explícitamente. El número de filas depende de las propiedades de las columnas y las celdas. El número de celdas también puede afectar al número de filas. La tabla puede tener una altura mayor que la suma de las alturas de todas sus filas. Las filas pueden tener menos celdas que el número de columnas. Y también es posible que las columnas tengan menos celdas que el número de filas.
PdfDocumentBuilder.Create().Generate("table-basic.pdf", doc =>
{
doc.Pages(page =>
{
page.Size(300, 100);
page.Content()
.Padding(10)
//.MinimalBox()
.Border(b => b.Thickness(1).Color(new PdfRgbColor(250, 123, 5)))
.Table(table =>
{
table.Columns(columns =>
{
columns.ConstantColumn(100);
columns.RelativeColumn(1);
columns.RelativeColumn(3);
});
for (int i = 0; i < 10; i++)
{
table.Cell()
.Border(b => b.Thickness(0.1))
.AlignCenter()
.Text($"Cell {i + 1}");
}
});
});
});
Puede ver el resultado del código en table-basic.pdf.
En el PDF resultante, la tabla ocupa todo el espacio del contenedor padre. Aunque no hay suficientes celdas para cubrir el área. Descomente la llamada MinimalBox para limitar la altura de la tabla a la suma de las alturas de sus filas.
El código define tres columnas y agrega 10 celdas a la tabla. La tabla coloca las celdas una tras otra y agrega una nueva fila cuando es necesario. Está perfectamente bien tener una fila con una sola celda.
La tabla colocará las celdas en la página siguiente si la página actual no tiene suficiente espacio. Puede observarlo aumentando el número de celdas agregadas.
Celdas
Permítame explicar lo que Layout API proporciona para trabajar con celdas de tabla.
Posición
Hay dos formas de crear una celda de tabla:
- sin información explícita de posición
- con una posición especificada al menos parcialmente
Usé la primera forma en el código de la sección anterior. Usted llama a la sobrecarga del método Cell que no acepta parámetros. El método agrega una nueva celda a la columna después de la última celda agregada. Si no hay espacio a la derecha, la celda pasa a la fila siguiente. En modo RTL, el método comprueba si hay espacio a la izquierda de la última celda agregada.
Si conoce la posición exacta de la nueva celda, use la otra sobrecarga del método Cell. La que acepta un delegado de tipo Action<TableCell>. En el código del delegado, especifique la fila y el índice de la celda llamando a los métodos RowIndex y ColumnIndex del objeto proporcionado.
Es posible especificar solo un índice de fila o de columna para la nueva celda. El índice de columna es 0 cuando solo especifica un índice de fila. Y viceversa.
Al crear celdas, puede combinar llamadas a ambas sobrecargas de Cell en cualquier orden.
Usaré el siguiente método de extensión en los próximos ejemplos de código de este artículo. Esto debería hacer que los ejemplos sean más concisos y fáciles de leer.
static class LayoutHelpers
{
public static TextSpan BoxWithText(this LayoutContainer cell, string caption)
=> cell.Border(b => b.Thickness(0.5))
.Background(new PdfGrayColor(75))
.ShowOnce()
.MinWidth(50)
.MinHeight(50)
.Padding(10)
.AlignCenter()
.AlignMiddle()
.Text(caption);
}
Aquí hay un ejemplo que crea una tabla con celdas colocadas tanto explícita como implícitamente. Usé el método de extensión para aplicar estilo y texto a las celdas. Los números de las celdas reflejan el orden de creación de las celdas.
PdfDocumentBuilder.Create().Generate("table-cells.pdf", doc =>
{
doc.Pages(page =>
{
page.Size(300, 200);
page.Content()
.Padding(10)
.MinimalBox()
.Border(b => b.Thickness(0.1))
.Table(table =>
{
table.Columns(columns =>
{
for (int i = 0; i < 4; i++)
columns.RelativeColumn();
});
table.Cell().BoxWithText("1");
table.Cell(c => c.RowIndex(1).ColumnIndex(1)).BoxWithText("2");
table.Cell().BoxWithText("3");
table.Cell(c => c.RowIndex(2).ColumnIndex(2)).BoxWithText("4");
table.Cell(c => c.RowIndex(0).ColumnIndex(3)).BoxWithText("5");
});
});
});
Puede ver el resultado del código en table-cells.pdf.
Intervalos de filas y columnas
Las celdas pueden abarcar varias filas y/o varias columnas. Use la sobrecarga de Cell que acepta un delegado para especificar el número de filas y columnas que abarcará la celda.
PdfDocumentBuilder.Create().Generate("table-cellspans.pdf", doc =>
{
doc.Pages(page =>
{
page.Size(300, 150);
page.Content()
.Padding(10)
.MinimalBox()
.Border(b => b.Thickness(0.1))
.Table(table =>
{
table.Columns(columns =>
{
for (int i = 0; i < 4; i++)
columns.RelativeColumn();
});
table.Cell(c => c.RowSpan(2).ColumnSpan(2)).BoxWithText("1");
table.Cell(c => c.ColumnSpan(2)).BoxWithText("2");
table.Cell().BoxWithText("3");
table.Cell().BoxWithText("4");
});
});
});
Puede ver el resultado del código en table-cellspans.pdf.
Superposición
Es posible que las celdas se superpongan entre sí. Cuando esto ocurre, el orden de creación define qué celda quedará encima de otra.
Puede obtener algunas celdas superpuestas cuando sus celdas abarcan más de una columna o fila. O cuando posiciona celdas tanto explícita como implícitamente.
PdfDocumentBuilder.Create().Generate("table-overlapping.pdf", doc =>
{
doc.Pages(page =>
{
page.Size(300, 300);
page.Content()
.Padding(10)
.MinimalBox()
.Border(b => b.Thickness(0.1))
.Table(table =>
{
table.Columns(columns =>
{
for (int i = 0; i < 4; i++)
columns.RelativeColumn();
});
for (int i = 0; i < 16; i++)
table.Cell().BoxWithText($"{i + 1}");
table.Cell(c => c.RowIndex(2).ColumnIndex(1).ColumnSpan(3))
.Background(new PdfRgbColor(250, 123, 5), 50);
});
});
});
Puede ver el resultado del código en table-overlapping.pdf.
Extender hasta el fondo
Si el diseño de su tabla es complejo, el mecanismo de paginación puede dejar un espacio en blanco en la parte inferior de algunas de sus columnas. Use el método ExtendCellsToBottom si quiere eliminar ese espacio en blanco. El método extiende la última celda de cada columna para que las celdas terminen en la parte inferior de la tabla.
En el siguiente ejemplo, la primera página muestra el comportamiento predeterminado. La segunda página muestra cómo la llamada ExtendCellsToBottom afecta a las columnas.
PdfDocumentBuilder.Create().Generate("table-extendcells.pdf", doc =>
{
for (int take = 0; take < 2; take++)
{
doc.Pages(page =>
{
page.Size(300, 200);
page.Content()
.Padding(10)
.MinimalBox()
.Border(b => b.Thickness(0.1))
.Table(table =>
{
if (take != 0)
table.ExtendCellsToBottom();
table.Columns(columns =>
{
for (int i = 0; i < 4; i++)
columns.RelativeColumn();
});
table.Cell(c => c.RowIndex(0).ColumnIndex(0)).BoxWithText("1");
table.Cell(c => c.RowIndex(2).ColumnIndex(0)).BoxWithText("2");
table.Cell(c => c.RowIndex(1).ColumnIndex(1)).BoxWithText("3");
table.Cell(c => c.RowIndex(2).ColumnIndex(2)).BoxWithText("4");
table.Cell(c => c.RowIndex(1).ColumnIndex(3)).BoxWithText("5");
});
});
}
});
Puede ver el resultado del código en table-extendcells.pdf.
Encabezado y pie
Las tablas pueden tener un encabezado y un pie. Use los métodos Header y Footer para acceder y configurar el correspondiente TableCellContainer. El contenedor proporciona los métodos Cell para crear celdas. Esos métodos funcionan exactamente igual que los métodos para el contenido principal de la tabla.
Las celdas del encabezado, el pie y el contenido principal usan la misma definición de columnas. Pero las tres colecciones de celdas son independientes y no se afectan entre sí.
Cuando la tabla no cabe en una sola página, el encabezado y el pie se repiten en cada página ocupada por la tabla.
Usé el método de extensión BoxWithText en los ejemplos anteriores. También uso el método de extensión WhiteBoxWithText para el siguiente código.
static class LayoutHelpers
{
public static TextSpan WhiteBoxWithText(
this LayoutContainer cell, string caption, bool center = true)
{
return cell.Border(b => b.Thickness(0.5))
.ShowOnce()
.MinWidth(50)
.MinHeight(50)
.Padding(10)
.Container(l => center ? l.AlignCenter() : l)
.AlignMiddle()
.Text(caption);
}
}
El siguiente ejemplo muestra cómo crear una tabla con un encabezado. Uso una tabla con cinco elementos químicos esenciales. Hay el nombre y el punto de fusión en grados Celsius y Kelvin para cada elemento.
var elements = new (string Name, double Celsius, double Kelvin)[] {
("Oxygen", -218.79, 54.36),
("Carbon", double.NaN, double.NaN),
("Hydrogen", -259.16, 13.99),
("Nitrogen", -209.86, 63.23),
("Sulfur", 115.21, 388.36),
};
static string formatDouble(double val)
{
return double.IsNaN(val)
? string.Empty
: val.ToString(CultureInfo.InvariantCulture);
}
PdfDocumentBuilder.Create().Generate("table-header.pdf", doc =>
{
doc.Pages(page =>
{
page.Size(400, 500);
page.Content()
.Padding(10)
.MinimalBox()
.Border(b => b.Thickness(0.1))
.Table(table =>
{
table.Columns(columns =>
{
columns.RelativeColumn();
columns.ConstantColumn(100);
columns.ConstantColumn(100);
});
table.Header(header =>
{
header.Cell(c => c.RowSpan(2)).BoxWithText("Chemical element");
header.Cell(c => c.ColumnSpan(2)).BoxWithText("Melting point");
header.Cell().BoxWithText("Celsius");
header.Cell().BoxWithText("Kelvin");
});
foreach (var (Name, Celsius, Kelvin) in elements)
{
table.Cell().WhiteBoxWithText(Name, false);
table.Cell().WhiteBoxWithText(formatDouble(Celsius));
table.Cell().WhiteBoxWithText(formatDouble(Kelvin));
}
});
});
});
Puede ver el resultado del código en table-header.pdf.
Código de muestra
Dedique algo de tiempo a revisar el ejemplo Agregar tablas a documentos PDF. También muestra cómo crear tablas con encabezados, pero no usa ningún método de extensión. Y también hay una versión de VB.NET.