该页面可以包含自动翻译的文本。
Table 容器
使用 Table 容器来布局最复杂的数据。表格在 PDF 文档中起着至 关重要的作用,可以提高文档的清晰度和有效性。
表格提供了一种结构化的格式来呈现数据。它们允许您以简洁且视觉上有吸引力的方式呈现复杂的细节。您可以 使用表格简洁地呈现事实、数据和趋势,而无需冗长的段落。
精心设计的表格可提高可读性。通过对齐列和行,您可以创建引导读者视线的结构。您可以使用背景、边框和字 体样式来强调特定的单元格或标题。
通过调用 LayoutContainer.Table 方法获取表格 容器。然后必须在容器中定义至少一个列。最简单的情况下,可以通过多次调用 Cell 方法来填充所有列和行。
请继续阅读以了解如何定义列、向表添加页眉和/或页脚。本文还描述了 Table 容器的所有其他功能。
本文是有关用于 PDF 生成的 Layout API 的系列文章的一部分。 如果您是 API 新手,请先阅读 Layout API 入门 部分。
9.5.17585-dev 9.5.17585-dev14,810 通过 NuGet 总下载量 4,858,021
列和行
每个表必须定义至少一个列。使用 Table.Columns 方法定
义列。该方法接受
Action
<TableColumnContainer> 类型的委托。
在委托代码中,通过调用所提供对象的方法向表中添加列。
ConstantColumn 方法添加一个宽 度等于精确点数的列。
RelativeColumn 方法添加具有相
对宽度的列。该方法接受列应占据的部分数。部分总数是此表中所有 RelativeColumn
调用的所有数字的总
和。大多数情况下,此方法的工作原理与 Row 容器的 RelativeItem
相同。请阅读链接以
获取详细说明。
无需明确定义行。行数取决于列和单元格属性。单元格数也会影响行数。表的高度可以大于所有行高的总和。行 的单元格数可以少于列数。列的单元格数也可以少于行数。
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}");
}
});
});
});
您可以在 table-basic.pdf 中看到代码的结果。
在生成的 PDF 中,表格占据了所有父容器空间。即使没有足够的单元格来覆盖该区域。取消注释 MinimalBox 调用以将表格高度限制为其行 高的总和。
代码定义了三列,并向表格添加了 10 个单元格。表格将单元格一个接一个地放置,并在需要时添加新行。一行 只有一个单元格是完全没问题的。
如果当前页面空间不足,表格会将单元格放在下一页。您可以通过增加添加的单元格数量来观察这一点。
细胞
让我解释一下 Layout API 为处理表格单元格提供了什么。
位置
有两种方法可以创建表格单元格:
- 不带明确的位置信息
- 至少部分指定位置
我在上一节的代码中使用了第一种方法。您调用不接受参数的 Cell 方法重载。该方法在最后一个添加的单元格后的列中添 加一个新单元格。如果右侧没有空间,则单元格将进入下一行。在 RTL 模式下,该方法会检查最后一个添加的单 元格左侧的空间。
如果您知道新单元格的确切位置,请使用 Cell
方法的另一个重载。该方法接受
Action
<TableCell> 类型的委托。在委托代码中,通过调用
所提供对象的 RowIndex 和
ColumnIndex 方法指定单元格行和索引。
可以为新单元格仅指定行或列索引。如果仅指定行索引,则列索引为 0。反之亦然。
创建单元格时,您可以按任意顺序混合对两个 Cell
重载的调用。
我将在本文的下一个代码示例中使用以下 扩展方法。这将使示例更加简洁且更易于阅读。
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);
}
下面是一个创建表格的示例,其中既有显式放置的单元格,也有隐式放置的单元格。我使用扩展方法将样式和文 本应用于单元格。单元格中的数字反映了单元格的创建顺序。
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");
});
});
});
您可以在 table-cells.pdf 中看到代码的结果。
行和列的跨度
单元格可以跨越多行和/或多列。使用接受委托的 Cell 重载 来指定单元格跨越的行数和列数。
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");
});
});
});
您可以在 table-cellspans.pdf 中看到代码的结果。
重叠
细胞之间可以相互覆盖。当这种情况发生时,产生的顺序决定了哪个细胞将位于另一个细胞之上。
当单元格跨越多列或多行时,或者当您显式或隐式地定位单元格时,可能会出现一些重叠单元格。
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);
});
});
});
您可以在 table-overlapping.pdf 中看到代码的结 果。
延伸至底部
如果表格布局复杂,分页机制可能会导致某些列底部出现空白。如果要消除空白,请使用 ExtendCellsToBottom 方法。该方法会扩展 每列的最后一个单元格,使单元格结束于表格底部。
在以下示例中,第一页显示默认行为。第二页显示 ExtendCellsToBottom
调用如何影响列。
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");
});
});
}
});
您可以在 table-extendcells.pdf 中看到代码的结 果。
页眉和页脚
表格可以有页眉和页脚。使用 Header 和 Footer 方法访问和设置相应的 TableCellContainer。容器提供 Cell 方法来创建单元格。这些方法的工作方式 与主表格内容的方法完全相同。
页眉、页脚和主表单元格使用相同的列定义。但这三个单元格集合都是独立的,不会相互影响。
当表格无法容纳在一页中时,页眉和页脚会在表格占据的每一页上重复。
我在前面的例子中使用了 BoxWithText
扩展方法。我还在下一个代码中使用了 WhiteBoxWithText
扩展方
法。
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);
}
}
以下示例显示如何创建带有标题的表格。我使用包含五种基本化学元素的表格。每个元素都有名称和熔点(摄氏 度和开尔文度)。
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));
}
});
});
});
您可以在 table-header.pdf 中看到代码的结果。
示例代码
请花点时间查看 将表格添加到 PDF 文档 示例。它还展示了如何创建带标题的表格,但不使用任何扩展方法。 并且还有一个 VB.NET 版本。