Questa pagina può contenere testo tradotto automaticamente.

Dimensione, posizione e rendering dei contenitori

Il contenuto è la parte più importante di un documento. Su questo non ci sono dubbi. Un'altra parte fondamentale è la formattazione, che crea una comunicazione chiara, professionale ed efficace. Un documento formattato correttamente è visivamente piacevole, leggibile e facile da navigare.

Potresti già sapere come organizzare il contenuto usando i contenitori. E come applicare loro un colore di sfondo. Questo articolo descrive come specificare dimensione e posizione per i contenitori. Copre anche funzionalità avanzate come il rendering condizionale del contenuto. Sono presenti informazioni sul supporto per le direzioni del contenuto da destra a sinistra.

Posizionamento dei contenitori

La classe LayoutContainer offre tutto ciò che serve per disporre i contenitori in modo professionale. Applicando padding e allineamento, puoi creare un documento che lascia un'impressione positiva sui suoi utenti.

Questo articolo fa parte di una serie su Layout API per la generazione di PDF. Se sei nuovo dell'API, leggi prima la parte Guida introduttiva a Layout API.

Dimensione

Per impostazione predefinita, i contenitori occupano l'area più piccola richiesta dal loro contenuto. In altre parole, la dimensione del contenitore è uguale alla dimensione intrinseca del suo contenuto.

La dimensione intrinseca di un'immagine è determinata dalle dimensioni del file immagine stesso. La dimensione intrinseca di uno span di testo è la dimensione dell'area che copre tutti i glifi nello span.

La dimensione di un contenitore composto, come Column o Table, dipende dalla dimensione delle parti del contenitore.

Width & Height

È possibile specificare una larghezza e un'altezza esatte di un contenitore usando i metodi Width e Height. Questo è molto comodo per i contenitori segnaposto.

Una dimensione esatta funziona bene anche per le immagini. Questo perché Layout API le ridimensiona per adattarle o riempire il contenitore, a seconda del loro ImageContentMode.

Bisogna fare attenzione con dimensioni esatte per i contenitori composti e per i contenitori con testo. Si otterrà una LayoutException quando non è possibile adattare un contenuto alla dimensione fornita.

Ci sono casi in cui vuoi impostare solo un vincolo sulla larghezza o sull'altezza. Puoi impostare vincoli usando i metodi MinWidth, MinHeight, MaxWidth e MaxHeight.

Nota che la libreria genererà una LayoutException quando non è possibile soddisfare i vincoli.

Extend

Un contenitore può estendersi per occupare il massimo spazio disponibile. Questo è utile quando non conosci una dimensione esatta o dei vincoli di dimensione.

Usa il metodo ExtendHorizontal quando vuoi che il contenitore occupi tutto lo spazio disponibile solo nella direzione orizzontale. Il metodo ExtendVertical è utile quando vuoi estendere il contenitore solo nella direzione verticale. Il metodo Extend fa sì che il contenitore occupi tutto lo spazio disponibile in entrambe le direzioni.

var gray = new PdfGrayColor(75);
var text = "Content goes here";
var size = new PdfSize(150, 50);

PdfDocumentBuilder.Create().Generate("positioning-extend.pdf", doc =>
{
    for (int i = 0; i < 4; i++)
    {
        doc.Pages(page =>
        {
            page.Size(size);
            page.Content().Row(r =>
            {
                var container = r.AutoItem().Background(gray);
                switch (i)
                {
                    case 0:
                        container.Text(text);
                        break;

                    case 1:
                        container.ExtendHorizontal().Text(text);
                        break;

                    case 2:
                        container.ExtendVertical().Text(text);
                        break;

                    case 3:
                        container.Extend().Text(text);
                        break;
                }
            });
        });
    }
});

Il risultato del codice precedente è in positioning-extend.pdf. Come puoi vedere, ciascuna delle quattro pagine contiene lo stesso testo su uno sfondo grigio. Ma la dimensione del contenitore è diversa in ogni pagina.

MinimalBox

La classe LayoutContainer fornisce il metodo MinimalBox. È in un certo senso l'opposto dei metodi Extend. Il metodo MinimalBox produce contenitori annidati che usano solo lo spazio minimo necessario per il contenuto.

var gray = new PdfGrayColor(75);
var size = new PdfSize(150, 50);

PdfDocumentBuilder.Create().Generate("positioning-minimalbox.pdf", doc =>
{
    doc.Pages(page =>
    {
        page.Size(size);
        page.Content().MinimalBox().Background(gray).Text("I don't want more space");
    });

    doc.Pages(page =>
    {
        page.Size(size);
        page.Content().Background(gray).Text("I'll take everything");
    });
});

Il risultato del codice precedente è in positioning-minimalbox.pdf. A causa della chiamata MinimalBox, il testo nella prima pagina occupa solo lo spazio richiesto. Nella seconda pagina, il testo copre l'intera pagina.

Scale

È possibile scalare qualsiasi contenuto in un contenitore. Il metodo Scale influisce sul contenuto in entrambe le direzioni, orizzontale e verticale. Usa il metodo ScaleHorizontal o ScaleVertical per cambiare il contenuto in una sola direzione. Gli ultimi due metodi non preservano il rapporto d'aspetto del contenuto.

Valori di scala inferiori a 1 riducono l'area occupata da un contenitore. Valori maggiori di 1 aumentano l'area. Per capovolgere il contenuto in un contenitore, usa un valore di scala negativo. Ad esempio, ScaleVertical(-1) produce una versione capovolta del contenuto originale.

PdfDocumentBuilder.Create().Generate("positioning-scale.pdf", doc =>
{
    doc.Pages(page =>
    {
        page.Content()
            .MinimalBox()
            .Column(column =>
            {
                var scales = new[] { 0.5f, 0.75f, 1, 1.3f, 1.5f };

                foreach (var scale in scales)
                {
                    var percent = (int)(scale * 100);
                    column.Item()
                        .Scale(scale)
                        .Text(FormattableString.Invariant($"Scale equals {scale} ({percent}%)."))
                            .FontSize(20);

                    column.Item().LineHorizontal(0.5);
                }
            });
    });
});

Il risultato del codice precedente è in positioning-scale.pdf.

ScaleToFit

Puoi ridurre la scala del contenuto per adattarlo allo spazio disponibile. Ad esempio, quando hai un'area fissa in cui visualizzare il nome o l'indirizzo di una persona. Naturalmente, puoi aumentare l'area nel caso di un nome più lungo. Ma un approccio più semplice potrebbe essere ridurre un po' la scala del testo. Usa il metodo ScaleToFit per ridurre la scala del contenuto.

ScaleToFit preserva il rapporto d'aspetto del contenuto. Il metodo non rende mai il contenuto più grande. Nota che questo metodo esegue calcoli iterativi. Questo potrebbe rallentare il processo di generazione del PDF.

PdfDocumentBuilder.Create().Generate("positioning-scaletofit.pdf", doc =>
{
    doc.Pages(page =>
    {
        page.Content().Column(column =>
        {
            for (int i = 0; i < 5; i++)
            {
                column.Item()
                    .Width(230 - 20 * i)
                    .Height(20)
                    .ScaleToFit()
                    .Border(b => b.Thickness(0.5))
                    .Text(" This text should fit into the changing width.");
            }
        });
    });
});

Il risultato del codice precedente è in positioning-scaletofit.pdf.

AspectRatio

Il rapporto d'aspetto definisce la relazione proporzionale tra la larghezza e l'altezza di un contenitore. Per trovare il rapporto d'aspetto di un contenitore, dividi la sua larghezza per la sua altezza.

Usa il metodo AspectRatio per specificare il rapporto d'aspetto di un contenitore. È utile quando progetti un contenitore riutilizzabile per layout o dimensioni di pagina diversi.

PdfDocumentBuilder.Create().Generate("positioning-aspectratio.pdf", doc =>
{
    var ratios = new double[] { 0.25, 0.5, 1, 2 };
    foreach (var ratio in ratios)
    {
        var ratioText = ratio.ToString(CultureInfo.InvariantCulture);
        doc.Pages(page =>
        {
            page.Size(200, 200);
            page.Content().Column(column =>
            {
                column.Item()
                    .AspectRatio(ratio)
                    .Background(new PdfGrayColor(75))
                    .Text($"Width / Heigth = {ratioText}");
            });
        });
    }
});

Il risultato del codice precedente è in positioning-aspectratio.pdf.

Il metodo ha il parametro opzionale di tipo AspectRatioMode. Usa questo parametro per specificare come ridimensionare il contenuto mantenendo il rapporto d'aspetto.

Un contenitore con un rapporto d'aspetto specificato occupa quanto più spazio possibile. A seconda della modalità, il contenitore tenterà di occupare l'intera area disponibile (predefinita), la larghezza o l'altezza.

Nota che la libreria può generare una LayoutException. Accade quando non può soddisfare i requisiti di dimensione, rapporto d'aspetto e modalità del rapporto d'aspetto.

Unconstrained

I contenitori possono non avere alcun vincolo di dimensione. Usa il metodo Unconstrained per rimuovere tutti i vincoli di dimensione da un contenitore.

Il contenuto in un contenitore senza vincoli occupa uno spazio con dimensione uguale alla dimensione intrinseca del contenuto. Il contenitore senza vincoli, di per sé, non occupa alcuno spazio. Di conseguenza, i contenitori fratelli possono coprire il contenuto del contenitore senza vincoli.

PdfDocumentBuilder.Create().Generate("positioning-unconstrained.pdf", doc =>
{
    doc.Pages(page =>
    {
        page.Content().MinimalBox()
            .Border(b => b.Thickness(0.5))
            .Column(column =>
            {
                column.Item().Text("First item");

                column.Item().Unconstrained()
                    .Text("Second item ignores all size constraints");

                // usando una riga vuota per il terzo elemento
                column.Item().Text(new string(' ', 20))
                    .BackgroundColor(new PdfRgbColor(187, 237, 237), 50);

                column.Item().Text("Fourth item");
            });
    });
});

Il risultato del codice precedente è in positioning-unconstrained.pdf. Nel codice, ho usato una riga di spazi con uno sfondo semitrasparente per il terzo elemento nella colonna. Come puoi vedere, il terzo elemento copre parzialmente il secondo elemento (senza vincoli).

Posizione

La posizione di un contenitore dipende da diversi fattori. Alcuni di essi sono l'allineamento, il padding, la posizione del contenitore padre e la direzione del contenuto. Per impostazione predefinita, qualsiasi contenitore si ancora alla posizione disponibile più a sinistra e più in alto.

Padding

Uno dei requisiti più comuni è aggiungere dello spazio attorno al contenuto del contenitore. La classe LayoutContainer fornisce un insieme di metodi per impostare l'area di padding di un contenitore. L'area di padding è lo spazio tra il contenuto e il bordo. In altre parole, il padding rappresenta lo spazio interno che circonda il contenuto.

Il metodo Padding imposta il padding su tutti e quattro i lati di un contenitore in una sola volta. Usa il metodo PaddingHorizontal per specificare il padding solo sui lati sinistro e destro. PaddingVertical fa lo stesso solo sui lati superiore e inferiore. Per impostare il padding in modo individuale su un lato, usa uno dei metodi PaddingTop/Bottom/Left/Right.

Align

Per cambiare la posizione di un contenitore, usa i metodi di allineamento. I metodi AlignLeft/AlignCenter/AlignRight applicano un allineamento orizzontale e restituiscono un contenitore annidato. I metodi AlignTop/AlignMiddle/AlignBottom restituiscono un contenitore annidato con il corrispondente allineamento verticale.

Un contenitore con allineamento applicato esplicitamente occupa l'area con larghezza e/o altezza minima richiesta. Il codice seguente crea una colonna con due elementi. Un elemento ha un allineamento applicato esplicitamente.

PdfDocumentBuilder.Create().Generate("positioning-alignment.pdf", doc =>
{
    var color = new PdfRgbColor(187, 237, 237);
    var text = "Hello";
    doc.Pages(page =>
    {
        page.Size(200, 100);
        page.Content().Column(c =>
        {
            c.Item().Extend().Background(color).Text(text);
            c.Item().Extend().AlignLeft().Background(color).Text(text);
        });
    });
});

La chiamata Extend fa sì che entrambi gli elementi occupino l'intera pagina. Chiamo il metodo AlignLeft sul secondo elemento. Questa chiamata non cambia la posizione perché il contenitore dell'elemento allinea il testo a sinistra per impostazione predefinita. Ma l'allineamento applicato esplicitamente cambia l'area occupata dal secondo elemento.

Il risultato del codice precedente è in positioning-alignment.pdf.

Translate

Per riposizionare un contenitore orizzontalmente e/o verticalmente, usa i metodi Translate/TranslateX/TranslateY. Il primo sposta i contenitori sia orizzontalmente sia verticalmente. Gli altri due spostano i contenitori in una sola direzione.

Tutti questi metodi sovrascrivono la posizione ma preservano i vincoli di dimensione. Il contenitore spostato può sovrapporsi ad altri contenitori. Usa valori negativi dei parametri per spostare a sinistra e/o verso l'alto. Valori positivi causano uno spostamento a destra e/o verso il basso.

PdfDocumentBuilder.Create().Generate("positioning-translate.pdf", doc =>
{
    doc.Pages(page =>
    {
        page.Size(200, 100);
        page.Content().Row(r =>
        {
            r.ConstantItem(50)
                .Background(new PdfRgbColor(187, 237, 237))
                .Text("Left");

            r.ConstantItem(50)
                // spostando questo elemento di 10 punti a sinistra e di 5 punti più in basso
                .Translate(-10, 5)
                .Background(new PdfRgbColor(15, 130, 9))
                .Text("Right");
        });
    });
});

Il risultato del codice precedente è in positioning-translate.pdf.

Rotate

Il contenuto ruotato, soprattutto il testo, può migliorare i documenti in modi diversi. Ad esempio, puoi risparmiare spazio e rendere il documento più coinvolgente e gradevole dal punto di vista estetico.

La classe LayoutContainer offre due approcci per ruotare il contenuto. Indipendentemente dall'approccio usato, il contenitore con il contenuto ruotato rispetta i vincoli di posizione e dimensione.

Rotazione di 90 gradi

I metodi RotateRight e RotateLeft ruotano il contenuto rispettivamente di 90 gradi in senso orario e antiorario.

Il codice seguente mostra come creare un documento con testo verticale accanto al contenuto principale della pagina.

PdfDocumentBuilder.Create().Generate("positioning-rotate.pdf", doc =>
{
    var lightGray = new PdfGrayColor(90);
    doc.Pages(page =>
    {
        page.Size(298, 210);
        page.Content().Row(r =>
        {
            r.AutoItem()
                .RotateLeft()
                .Background(lightGray)
                .Text("This content goes up");

            r.RelativeItem(1)
                .ExtendVertical()
                .PaddingHorizontal(10)
                .Column(t =>
                {
                    for (int i = 0; i < 15; i++)
                        t.Item().Text("The main content line goes here");
                });

            r.AutoItem()
                .RotateRight()
                .Background(lightGray)
                .Text("This content goes down");
        });
    });
});

Il risultato del codice precedente è in positioning-rotate.pdf.

Rotazione a qualsiasi angolo

Il metodo Rotate ruota il contenuto di un numero arbitrario di gradi. I numeri positivi causano una rotazione in senso orario. I numeri negativi sono per la rotazione in senso antiorario.

Il punto di origine della rotazione è l'angolo in alto a sinistra del contenitore. Il contenuto ruotato può sovrapporsi ad altri contenitori.

PdfDocumentBuilder.Create().Generate("positioning-rotate2.pdf", doc =>
{
    doc.Pages(page =>
    {
        page.Size(298, 210);
        page.Content()
            .Padding(25)
            .Background(new PdfGrayColor(70)) // gray
            .AlignCenter()
            .AlignMiddle()

            .Background(new PdfGrayColor(100)) // white

            .Rotate(30)

            .Width(100)
            .Height(100)
            .Background(new PdfRgbColor(187, 237, 237)); // blue
    });
});

Il risultato del codice precedente è in positioning-rotate2.pdf.

Per cambiare il punto di origine della rotazione, chiama uno dei metodi Translate prima della chiamata Rotate. Non dimenticare di traslare di nuovo l'origine dopo la chiamata.

// trasla il punto di origine della rotazione
.TranslateX(50)
.TranslateY(50)

.Rotate(30)

// trasla di nuovo indietro
.TranslateX(-50)
.TranslateY(-50)

Layout condizionale

Il layout del tuo documento PDF può dipendere da una condizione. Ad esempio, puoi usare un allineamento diverso o un colore di sfondo diverso per le righe pari e dispari in una colonna.

Usa il metodo Container per inserire un contenitore annidato con un layout che dipende da una condizione. La chiamata a questo metodo non interromperà la catena di chiamate.

PdfDocumentBuilder.Create().Generate("positioning-container.pdf", doc =>
{
    doc.Pages(page =>
    {
        page.Content().Column(c =>
        {
            for (int i = 0; i < 15; i++)
            {
                c.Item()
                    .TextStyle(TextStyle.Parent.FontSize(14))
                    .Container(x => i % 2 == 0 ? x.Background(new PdfGrayColor(70)) : x)
                    .Text($"Row {i + 1}");
            }
        });
    });
});

Il risultato del codice precedente è in positioning-container.pdf.

DSL

Alcune parti di un documento possono usare lo stesso layout. Ad esempio, possono impostare un bordo visivamente identico o usare la stessa formattazione. Secondo il principio del "non ripeterti", consiglio di estrarre il codice comune in un metodo.

Usare un metodo di estensione per il codice comune offre due vantaggi:

  • Puoi usare il metodo in catene di chiamate di metodi
  • Puoi avere un nome significativo per un insieme di chiamate di metodi

Dato questi vantaggi, puoi costruire un domain-specific language (DSL). Con il DSL, il codice del layout può essere più breve e più facile da comprendere.

static class LayoutHelpers
{
    public static LayoutContainer NumberCell(this Table table)
        => table.Cell().Border(b => b.Thickness(0.5)).PaddingHorizontal(10);
}

PdfDocumentBuilder.Create().Generate("positioning-dsl.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.NumberCell().Text($"{i + 1}");
    });
}));

Processo di rendering

L'estensione Layout organizza qualsiasi contenuto inserito in un contenitore in base ai vincoli di dimensione e posizione. Alcuni contenuti possono estendersi su più pagine. Esiste un ordine rigoroso in cui il contenuto viene renderizzato. Flusso del contenuto è un altro nome per questo ordine.

La classe LayoutContainer offre alcuni metodi per modificare il flusso del contenuto. Potresti non averne bisogno ogni volta, ma ci sono casi in cui non esiste altro modo per ottenere il layout richiesto.

PageBreak

Quando devi iniziare un blocco di contenuto da una nuova pagina, usa il metodo PageBreak. Ad esempio, puoi usare il metodo per iniziare un elemento Column da una nuova pagina.

Ecco un esempio di codice che divide una colonna in modo che ogni pagina contenga solo due righe.

PdfDocumentBuilder.Create().Generate("positioning-pagebreak.pdf", doc => doc.Pages(page =>
{
    page.Size(200, 100);
    page.Content().Column(c =>
    {
        for (int i = 1; i <= 10; ++i)
        {
            c.Item().Text($"Item {i}");

            if (i % 2 == 0)
                c.Item().PageBreak();
        }
    });
}));

Il risultato del codice precedente è in positioning-pagebreak.pdf.

ShowIf

In base a una condizione, potrebbe essere necessario mostrare/nascondere un contenitore. Esiste il metodo ShowIf, che essenzialmente è uno zucchero sintattico per questo caso speciale di layout condizionale.

Nel codice seguente, uso il metodo ShowIf per inserire una linea verticale dopo ogni 5 elementi in una riga.

PdfDocumentBuilder.Create().Generate("positioning-showif.pdf", doc => doc.Pages(page =>
{
    page.Size(200, 100);
    page.Content().Row(r =>
    {
        for (int i = 0; i < 10; ++i)
        {
            r.AutoItem().Text(i.ToString());
            r.AutoItem().ShowIf(i > 0 && (i + 1) % 5 == 0).LineVertical(0.5);
        }
    });
}));

Il risultato del codice precedente è in positioning-showif.pdf.

ShowOnce

Puoi impedire la ripetizione di un pezzo di contenuto nelle pagine successive. Usa il metodo ShowOnce per indicare al motore di layout di renderizzare completamente il contenuto una sola volta.

Controlla il codice seguente per vedere come la chiamata ShowOnce impedisce a "Environment" di apparire nella seconda pagina.

PdfDocumentBuilder.Create().Generate("positioning-showonce.pdf", doc => doc.Pages(page =>
{
    page.Size(200, 100);
    page.Content().Row(r =>
    {
        r.RelativeItem()
            .Background(new PdfGrayColor(75))
            .Border(b => b.Thickness(0.5))
            .Padding(5)
            .ShowOnce()
            .Text("Environment");

        r.RelativeItem()
            .Border(b => b.Thickness(0.5))
            .Padding(5)
            .Column(c =>
            {
                c.Item().Text(Environment.OSVersion.VersionString);
                c.Item().Text(string.Empty);
                c.Item().Text(
                    Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER")
                    ?? string.Empty
                );
            });
    });
}));

Il risultato del codice precedente è in positioning-showonce.pdf.

ShowEntire

Il comportamento predefinito è suddividere il contenuto tra le pagine quando non entra in una sola pagina. Usa il metodo ShowEntire per renderizzare l'intero contenitore su una sola pagina.

Nota che la libreria genera una LayoutException quando non è possibile adattare tutto il contenuto in una sola pagina.

A causa della chiamata ShowEntire nel codice seguente, il testo del secondo elemento inizia dalla seconda pagina. Senza la chiamata, inizierebbe nella prima pagina, subito dopo il testo del primo elemento.

PdfDocumentBuilder.Create().Generate("positioning-showentire.pdf", doc => doc.Pages(page =>
{
    page.Size(100, 100);
    page.Content().Column(c =>
    {
        c.Item().Text(t =>
        {
            for (var i = 0; i < 4; i++)
                t.Line($"First item line {i + 1}");
        });

        c.Item()
            .Background(new PdfRgbColor(250, 123, 5))
            .ShowEntire()
            .Text(t =>
            {
                for (var i = 0; i < 4; i++)
                    t.Line($"Second item line {i + 1}");
            });
    });
}));

Il risultato del codice precedente è in positioning-showentire.pdf.

EnsureSpace

In un certo senso, EnsureSpace è un caso speciale del metodo ShowEntire. La differenza è che EnsureSpace non richiede che tutto il contenuto entri in una pagina. Il metodo prova solo ad adattare una parte del contenuto con l'altezza specificata. Tutto il resto andrà nella pagina successiva.

Se l'area non occupata della pagina corrente ha un'altezza inferiore a quella richiesta, tutto il contenuto verrà renderizzato in una nuova pagina. In questo caso, il metodo produrrà lo stesso risultato del metodo ShowEntire.

StopPaging

Usa il metodo StopPaging per produrre l'output su al massimo una pagina. Chiamare questo metodo su un contenitore ne impedisce la paginazione. L'estensione Layout non suddividerà il contenuto di questo contenitore tra più pagine. Non renderizzerà alcun dato che non può entrare in una sola pagina.

Il codice di esempio seguente aggiunge due insiemi di pagine al documento. Entrambi gli insiemi usano come contenuto un elenco di nomi dei giorni della settimana. Il primo insieme ha una sola pagina, perché il codice chiama il metodo StopPaging per il contenitore del contenuto delle pagine.

PdfDocumentBuilder.Create().Generate("positioning-stoppaging.pdf", doc =>
{
    static Action<TextContainer> produceText(string heading)
    {
        var text = string.Join('\n', DateTimeFormatInfo.InvariantInfo.DayNames);
        return t =>
        {
            t.Line(heading).BackgroundColor(new PdfRgbColor(250, 123, 5));
            t.Span(text);
        };
    }

    doc.Pages(page =>
    {
        page.Size(100, 100);
        page.Content()
            .StopPaging()
            .Text(produceText("Without paging:"));
    });

    doc.Pages(page =>
    {
        page.Size(100, 100);
        page.Content()
            .Text(produceText("Default behaviour:"));
    });
});

Il risultato del codice precedente è in positioning-stoppaging.pdf.

SkipOnce

Puoi posticipare la comparsa del contenuto. Se un contenitore appare in più di una pagina, usa SkipOnce per saltare la prima pagina e renderizzare il contenuto in tutte le pagine a partire dalla seconda.

Questa capacità è utile per tutti i tipi di intestazioni, ma puoi usarla anche con altri contenuti. Controlla il codice seguente per vedere come la chiamata SkipOnce impedisce all'intestazione di apparire nella prima pagina.

PdfDocumentBuilder.Create().Generate("positioning-skiponce.pdf", doc => doc.Pages(page =>
{
    page.Size(298, 210);

    page.Header()
        .SkipOnce()
        .Text("This header will appear starting from page 2")
        .Style(TextStyle.Parent.Underline());

    page.Content().Column(c =>
    {
        for (int i = 0; i < 5; i++)
        {
            if (i > 0)
                c.Item().PageBreak();

            c.Item().Text($"Page {i + 1}");
        }
    });
}));

Il risultato del codice precedente è in positioning-skiponce.pdf.

Direzione del contenuto

La direzione predefinita del contenuto è da sinistra a destra. I contenitori allineano il loro testo e gli altri contenuti a sinistra.

Ma esistono lingue scritte da destra a sinistra (ad esempio arabo ed ebraico). Quando crei contenuti in queste lingue, usa il metodo ContentFromRightToLeft. Una sua chiamata cambierà la direzione del contenuto del contenitore da destra a sinistra. Il metodo cambierà anche l'allineamento predefinito.

Se la maggior parte del contenuto delle tue pagine è in una lingua RTL, puoi impostare la direzione del contenuto predefinita per le pagine su da destra a sinistra. Usa il metodo PageLayout.ContentFromRightToLeft per questo. Poi, per sovrascrivere la direzione del contenuto predefinita per contenitori selezionati, usa il metodo ContentFromLeftToRight.

Nota che la direzione del contenuto non influisce sull'allineamento specificato esplicitamente. Ad esempio, il contenuto allineato a destra rimarrà sul lato destro indipendentemente dalla direzione del contenuto impostata per il suo contenitore. L'ordine visivo degli elementi figlio sarà diverso a seconda della direzione del contenuto.