该页面可以包含自动翻译的文本。
容器及其内容
文档是一组页面。每个页面本身又是一组内容片段。正如您可能已经知道的,PageLayout 类为主要内容和附加内容提供了容器。但这些容器该如何使用呢?

容器有助于组织页面上的内容。放到页面上的任何内容都必须进入容器。如果内容足够大,一个容器可以跨越多个页面占用空间。
您可以将一些文本或图像放入容器中。出于对齐和定位的目的,您可以将一个容器放入另一个容器中。还有一些容器可容纳多于一个内容片段。
页面上的容器由 LayoutContainer 类的对象表示。使用此类来设置容器的大小、位置、内容和渲染过程。
本文是关于用于 PDF 生成的 Layout API 系列文章的一部分。如果您是第一次接触该 API,请先阅读 Layout API 入门 部分。
容器如何工作
首先获取一个容器。例如,调用 PageLayout.Content 方法。该方法会返回一个不占用空间且未设置任何内容或属性的容器。使用 LayoutContainer 类的方法来设置容器。
需要理解的一个非常重要的点是,所有 LayoutContainer 方法都会向容器中放入内容。当您向容器中添加一些文本时,这是符合预期的。但当您设置缩进或宽度时,内容会变成什么?
当您设置容器属性时,库会创建一个具有指定属性的新容器。新容器会成为原始容器的内容。库会将嵌套容器作为方法结果返回。
嵌套容器的属性会影响父容器,反之亦然。例如,嵌套容器的宽度会影响父容器的大小。父容器的默认文本样式会影响嵌套容器中的文本。Layout 附加组件会使用容器层次结构及其属性来构建最终布局。
以下代码的结果可能会让您感到意外,但请花些时间分析它。该代码演示了嵌套容器的工作方式。
PdfDocumentBuilder.Create().Generate("containers-how.pdf", doc => doc.Pages(page =>
{
page.Size(150, 150);
page.Content()
.Background(new PdfRgbColor(235, 64, 52)) // 红色
.PaddingTop(50)
.Background(new PdfRgbColor(187, 237, 237)) // 蓝色
.PaddingRight(50)
.Background(new PdfRgbColor(15, 130, 9)) // 绿色
.PaddingBottom(50)
.Background(new PdfRgbColor(250, 123, 5)) // 橙色
.PaddingLeft(50)
.Background(new PdfRgbColor(204, 204, 204)); // 灰色
}));
装饰
文档设计不仅仅是排列文本和图像。设计良好的文档不仅更有效,而且更具视觉吸引力。
使用 Layout API,您可以为任何容器应用背景色。这有助于在内容中建立层次结构。您还可以通过应用边框来定义边界。使用垂直线和水平线分隔内容元素。
PdfDocumentBuilder.Create().Generate("containers-decor.pdf", doc => doc.Pages(page =>
{
page.Size(150, 150);
page.Content()
.Background(new PdfRgbColor(250, 123, 5))
.Border(b =>
{
b.Color(new PdfGrayColor(0), 50);
b.Thickness(15);
})
.PaddingTop(74)
.LineHorizontal(2)
.Color(new PdfCmykColor(73, 45, 0, 4))
.DashPattern(new PdfDashPattern(new double[] { 8, 2 }));
}));
该 API 支持 灰度、RGB 和 CMYK 色彩空间中的不透明和半透明颜色。除了实线之外,Layout API 还支持使用 虚线样式 的线条。
上述代码的结果见 containers-decor.pdf。
内容
让我们看看 LayoutContainer 类为组织内容提供了什么。
Text
要向容器中添加文本,请使用 Text 方法之一。
如果所有文本都使用相同样式,请使用该方法的简写版本。该版本接受一个字符串并返回 TextSpan 对象。您可以使用该对象来设置该片段的文本样式。
Text 方法还有另一个版本,它接受类型为 Action<TextContainer> 的委托。使用该版本可以在一个文本块中包含不同样式的片段。TextContainer 提供了在文本片段之间插入图像和其他元素的方法。它还有其他高级功能,例如设置段落之间距离的能力。
PdfDocumentBuilder.Create().Generate("containers-text.pdf", doc => doc.Pages(page =>
{
page.Header().Text("This is a simple text span");
page.Content().Text(t =>
{
t.Span("This line contains ");
t.Span("some underlined text").Style(TextStyle.Parent.Underline());
});
}));
您可以在 containers-text.pdf 中查看代码结果。
Image
Layout API 提供了从文件或流中的图像数据创建 Image 对象的方法。任何 Image 对象都可以作为容器的内容。您可以在多个容器中使用同一个 Image 对象。不同的内容模式会影响图像在容器中的显示效果。
该库只能加载光栅格式的图像:PNG、JPEG、JPEG 2000、BMP、GIF 和 TIFF。
PdfDocumentBuilder.Create().Generate("containers-image.pdf", doc =>
{
var imageFile = new FileInfo(@"path-to-image.jpg");
var image = doc.Image(imageFile);
doc.Pages(pages =>
{
pages.Size(image.Width, image.Height);
pages.Content().Image(image, ImageContentMode.FitArea);
});
});
Column
列可为垂直依次排列的无限数量项提供空间。您可以在列中使用任何类型的项。例如,列可以包含图像和文本项。每个项的宽度等于列宽。每个项的高度取决于该项的内容和属性。
PdfDocumentBuilder.Create().Generate("containers-column.pdf", doc => doc.Pages(page =>
{
page.Content().Column(c =>
{
for (int i = 0; i < 10; i++)
{
PdfColor color = i % 2 == 0
? new PdfRgbColor(187, 237, 237)
: new PdfGrayColor(66);
c.Item().Background(color).Height(10 + i * 3);
}
});
}));
您可以在 containers-column.pdf 中查看代码结果。
有关 Column 容器功能的详细信息,请阅读 复合容器 文章。
Row
Row 容器有助于水平组织无限数量的项。行中的每个项都是一个容器。因此,您可以在一行中放入不同类型的内容。
var rowItems = new[] { "three", "two", "one" };
PdfDocumentBuilder.Create().Generate("containers-row.pdf", doc => doc.Pages(page =>
{
page.Content().Row(row =>
{
for (int index = 0; index < rowItems.Length; index++)
{
row.AutoItem().Text(rowItems[index]);
if (index != rowItems.Length - 1)
row.AutoItem().PaddingHorizontal(10).LineVertical(0.5);
}
});
}));
您可以在 containers-row.pdf 中查看代码结果。
复合容器 文章包含有关 Row 容器的详细信息。
Table
使用 Table 容器来布局最复杂的数据。先定义至少一列,然后通过多次调用 Cell 方法来填充列和行。
表可以有页眉和页脚。表中的单元格可以跨越多列和/或多行。下面的代码添加了一个简单表格。
PdfDocumentBuilder.Create().Generate("containers-table.pdf", doc => doc.Pages(page =>
{
page.Content().Table(t =>
{
t.Columns(c =>
{
for (int i = 0; i < 4; ++i)
c.ConstantColumn(50);
});
for (int i = 0; i < 16; i++)
{
t.Cell()
.Border(b => b.Thickness(0.5))
.PaddingHorizontal(10)
.Text($"{i + 1}");
}
});
}));
代码结果见 containers-table.pdf。
有关所有 Table 容器功能,请阅读 表格容器 文章。
Inlined
InlineContainer 容器类型提供了一种方便的方式,用于用容器集合中的项填充区域。您只需将项一个接一个地添加,库就会将它们依次排列成一行。如果没有空间放置某个项,库会开始新的一行。
有关 InlineContainer 容器的更多信息,请参见 复合容器 文章。
Layers
在某些情况下,将内容放在多个层上是最佳选择。LayerContainer 容器类型正是为此而设计。您必须定义恰好一个主层和任意数量的非主层。Layout API 会按您创建这些层的顺序对它们进行合成。
有关 LayerContainer 类型的更多细节,请阅读 复合容器。
Element
这是一种特殊的内容。您可以动态创建一个元素并将结果放入容器中。
动态创建的元素可以提供依赖于页码、大小和其他属性的布局。