Diese Seite kann automatisch übersetzten Text enthalten.

Tabellencontainer

Verwenden Sie Table-Container, um Ihre komplexesten Daten zu layouten. Tabellen spielen in PDF-Dokumenten eine entscheidende Rolle und verbessern deren Klarheit und Wirksamkeit.

Tabellen bieten ein strukturiertes Format zur Darstellung Ihrer Daten. Sie ermöglichen es Ihnen, komplexe Details prägnant und optisch ansprechend darzustellen. Statt langer Absätze können Sie Tabellen verwenden, um Fakten, Zahlen und Trends knapp zu präsentieren.

Eine gut gestaltete Tabelle verbessert die Lesbarkeit. Durch die Ausrichtung von Spalten und Zeilen schaffen Sie eine Struktur, die den Blick des Lesers lenkt. Sie können Hintergründe, Rahmen und Schriftarten verwenden, um bestimmte Zellen oder Überschriften hervorzuheben.

Tabellencontainer

Erstellen Sie einen Tabellencontainer, indem Sie die Methode LayoutContainer.Table aufrufen. Dann müssen Sie mindestens eine Spalte im Container definieren. Im einfachsten Fall können Sie alle Spalten und Zeilen füllen, indem Sie die Methode Cell mehrmals aufrufen.

Bitte lesen Sie weiter, um zu erfahren, wie Spalten definiert und einer Tabelle eine Kopf- und/oder Fußzeile hinzugefügt werden. Der Text beschreibt auch alle anderen Funktionen des Table-Containers.

Dieser Artikel ist Teil einer Reihe über Layout API zur PDF-Erstellung. Wenn Sie die API noch nicht kennen, lesen Sie zuerst den Abschnitt Erste Schritte mit Layout API.

Spalten und Zeilen

Jede Tabelle muss mindestens eine Spalte definieren. Verwenden Sie die Methode Table.Columns, um Spalten zu definieren. Die Methode akzeptiert einen Delegaten vom Typ Action<TableColumnContainer>. Im Delegaten-Code fügen Sie der Tabelle Spalten hinzu, indem Sie Methoden des bereitgestellten Objekts aufrufen.

Die Methode ConstantColumn fügt eine Spalte mit einer Breite hinzu, die genau einer bestimmten Anzahl von Punkten entspricht.

Die Methode RelativeColumn fügt eine Spalte mit relativer Breite hinzu. Die Methode akzeptiert die Anzahl der Teile, die die Spalte einnehmen soll. Die Gesamtzahl der Teile ist die Summe aller Zahlen in allen Aufrufen von RelativeColumn in dieser Tabelle. Meistens funktioniert diese Methode genauso wie RelativeItem des Row container. Bitte lesen Sie den Link für die detaillierte Erklärung.

Es ist nicht erforderlich, Zeilen explizit zu definieren. Die Anzahl der Zeilen hängt von Spalten- und Zelleneigenschaften ab. Auch die Anzahl der Zellen kann die Anzahl der Zeilen beeinflussen. Eine Tabelle kann eine größere Höhe haben als die Summe aller Zeilenhöhen. Zeilen können weniger Zellen als die Anzahl der Spalten haben. Und es ist möglich, dass Spalten weniger Zellen als die Anzahl der Zeilen haben.

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}");
                }
            });
    });
});

Das Ergebnis des Codes sehen Sie in table-basic.pdf.

Im resultierenden PDF belegt die Tabelle den gesamten Platz des übergeordneten Containers. Obwohl nicht genügend Zellen vorhanden sind, um die Fläche abzudecken. Kommentieren Sie den Aufruf von MinimalBox aus, um die Tabellenhöhe auf die Summe ihrer Zeilenhöhen zu begrenzen.

Der Code definiert drei Spalten und fügt der Tabelle 10 Zellen hinzu. Die Tabelle platziert die Zellen nacheinander und fügt bei Bedarf eine neue Zeile hinzu. Es ist völlig in Ordnung, eine Zeile nur mit einer Zelle zu haben.

Die Tabelle platziert Zellen auf der nächsten Seite, wenn auf der aktuellen Seite nicht genügend Platz vorhanden ist. Das können Sie beobachten, indem Sie die Anzahl der hinzugefügten Zellen erhöhen.

Zellen

Ich erkläre, was Layout API für die Arbeit mit Tabellenzellen bietet.

Position

Es gibt zwei Möglichkeiten, eine Tabellenzelle zu erstellen:

  • ohne explizite Positionsangaben
  • mit mindestens teilweise angegebener Position

Im Code des vorherigen Abschnitts habe ich die erste Möglichkeit verwendet. Sie rufen die Überladung der Methode Cell auf, die keine Parameter akzeptiert. Die Methode fügt eine neue Zelle in der Spalte nach der zuletzt hinzugefügten Zelle hinzu. Wenn rechts kein Platz ist, wechselt die Zelle in die nächste Zeile. Im RTL-Modus prüft die Methode den Platz links von der zuletzt hinzugefügten Zelle.

Wenn Sie die genaue Position für die neue Zelle kennen, verwenden Sie die andere Überladung der Methode Cell. Diejenige, die einen Delegaten vom Typ Action<TableCell> akzeptiert. Im Delegaten-Code geben Sie Zeilen- und Spaltenindex an, indem Sie die Methoden RowIndex und ColumnIndex des bereitgestellten Objekts aufrufen.

Es ist möglich, für die neue Zelle nur einen Zeilen- oder Spaltenindex anzugeben. Der Spaltenindex ist 0, wenn Sie nur einen Zeilenindex angeben. Und umgekehrt.

Beim Erstellen von Zellen können Sie Aufrufe beider Cell-Überladungen in beliebiger Reihenfolge kombinieren.

Die folgende Erweiterungsmethode verwende ich in den nächsten Codebeispielen in diesem Artikel. Dadurch werden die Beispiele knapper und leichter lesbar.

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);
}

Hier ist ein Beispiel, das eine Tabelle mit sowohl explizit als auch implizit platzierten Zellen erstellt. Ich habe die Erweiterungsmethode verwendet, um Zellen Stil und Text zuzuweisen. Die Zahlen in den Zellen spiegeln die Erstellungsreihenfolge der Zellen wider.

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");
            });
    });
});

Das Ergebnis des Codes sehen Sie in table-cells.pdf.

Zeilen- und Spaltenüberspannungen

Zellen können sich über mehrere Zeilen und/oder mehrere Spalten erstrecken. Verwenden Sie die Überladung der Methode Cell, die einen Delegaten akzeptiert, um die Anzahl der Zeilen und Spalten festzulegen, über die sich die Zelle erstreckt.

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");
            });
    });
});

Das Ergebnis des Codes sehen Sie in table-cellspans.pdf.

Überlappung

Es ist möglich, dass Zellen einander überdecken. Wenn das passiert, bestimmt die Erstellungsreihenfolge, welche Zelle über einer anderen liegt.

Überlappende Zellen können auftreten, wenn sich Ihre Zellen über mehr als eine Spalte oder Zeile erstrecken. Oder wenn Sie Zellen sowohl explizit als auch implizit positionieren.

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);
            });
    });
});

Das Ergebnis des Codes sehen Sie in table-overlapping.pdf.

Bis zum unteren Rand ausdehnen

Wenn das Layout Ihrer Tabelle komplex ist, kann der Seitenumbruchmechanismus am unteren Ende einiger Ihrer Spalten einen Leerraum verursachen. Verwenden Sie die Methode ExtendCellsToBottom, wenn Sie den Leerraum entfernen möchten. Die Methode verlängert die letzte Zelle in jeder Spalte so, dass die Zellen am unteren Rand der Tabelle enden.

Im folgenden Beispiel zeigt die erste Seite das Standardverhalten. Die zweite Seite zeigt, wie sich der Aufruf von ExtendCellsToBottom auf die Spalten auswirkt.

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");
                });
        });
    }
});

Das Ergebnis des Codes sehen Sie in table-extendcells.pdf.

Tabellen können eine Kopf- und eine Fußzeile haben. Verwenden Sie die Methoden Header und Footer, um auf den entsprechenden TableCellContainer zuzugreifen und ihn einzurichten. Der Container stellt die Methoden Cell zum Erstellen von Zellen bereit. Diese Methoden funktionieren genau wie die Methoden für den Hauptinhalt der Tabelle.

Kopfzeilen-, Fußzeilen- und Haupttabellenzellen verwenden dieselbe Spaltendefinition. Aber alle drei Zellensammlungen sind unabhängig und beeinflussen einander nicht.

Wenn die Tabelle nicht auf eine Seite passt, werden Kopf- und Fußzeile auf jeder von der Tabelle belegten Seite wiederholt.

Ich habe in den vorherigen Beispielen die Erweiterungsmethode BoxWithText verwendet. Für den nächsten Code verwende ich außerdem die Erweiterungsmethode 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);
    }
}

Das folgende Beispiel zeigt, wie man eine Tabelle mit Kopfzeile erstellt. Ich verwende eine Tabelle mit fünf wichtigen chemischen Elementen. Für jedes Element sind der Name und der Schmelzpunkt sowohl in Celsius als auch in Kelvin angegeben.

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));
                }
            });
    });
});

Das Ergebnis des Codes sehen Sie in table-header.pdf.

Beispielcode

Bitte nehmen Sie sich etwas Zeit, um das Beispiel Fügen Sie Tabellen zu PDF-Dokumenten hinzu anzusehen. Es zeigt auch, wie Tabellen mit Kopfzeilen erstellt werden, verwendet aber keine Erweiterungsmethoden. Außerdem gibt es eine VB.NET-Version, too.