該頁面可以包含自動翻譯的文字。

Table 容器

使用 Table 容器來佈局最複雜的資料。表格在 PDF 文件中發揮著 至關重要的作用,可以提高文件的清晰度和有效性。

表格提供了用於呈現資料的結構化格式。它們使您能夠以簡潔且具有視覺吸引力的方式呈現複雜的細節。您可以 使用表格來簡潔地呈現事實、數據和趨勢,而不是冗長的段落。

精心設計的表格可以增強可讀性。透過對齊列和行,您可以建立引導讀者視線的結構。您可以使用背景、邊框和 字體樣式來強調特定的儲存格或標題。

Table 容器

透過呼叫 LayoutContainer.Table 方法來取得一 個表格容器。然後您必須在容器中定義至少一列。在最簡單的情況下,您可以透過多次呼叫 Cell 方法來填入所有列和行。

請繼續閱讀以了解如何定義列、為表格新增頁首和/或頁尾。該文字還描述了 Table 容器的所有其他功能。

本文是用於 PDF 產生的 La​​yout API 的系列文章的一部分。 如果您是 API 新手,請先閱讀 Layout API 入 門 部分。

Docotic.Pdf 函式庫 9.5.17615-dev 佈局附加元件 9.5.17615-dev
回歸測試 14,813 已通過 NuGet 總下載量 4,924,084

列和行

每個表格必須至少定義一列。使用 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> 類型的委託。在委託程式碼中,透過呼 叫所提供物件的 RowIndexColumnIndex 方法來指定單元格行和索引。

可以為新單元格僅指定行或列索引。當僅指定行索引時,列索引為 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 中看到程式碼的結 果。

表格可以有頁首和頁尾。使用 HeaderFooter 方法來存取和設定對應的 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 版本。