Flow Documents – part 3 – pdf tables

Support for pdf tables is available in XFINIUM.PDF library through the flow content API and PdfFlowTableContentclass.

The table

To add a table to a pdf file you create a PdfFlowTableContent object, set up its properties and content and add the table object to the flow document.
When a table object is created, its number of columns must be specified. In this situation all columns have the same width. Alternatively the table object can be created with an array of column objects (instances of PdfFlowTableColumn class) specifying the distinct properties for each column.
The table takes all available space on horizontal. If the sum of column widths does not match the available width, the last column is adjusted to fill the available space.
The table’s Border property specifies the border to be drawn around cells. This border is used if the cells do no specify an explicit border.
The DefaultCell property specifies the default properties when cells are constructed automatically based on the type of input data (example 1).

The row

The table data is stored in a collection of rows. The Rows property (of type PdfFlowTableRowCollection) lets you add or remove rows from a table.
A row can have a minimum height. The row height can grow over this value if the content requires, but it cannot go below this value. When a row fits partially at the bottom of the page, its content is split in 2 if the available space is greater than row’s minimum height.

The cell

Each row has a collection of Cells (of type PdfFlowTableCellCollection). This collection lets you add or remove cells from a row. If the number of cells in a row is greater than number of table columns, the cells at the end are ignored.
If the number of cells in a row is less than number of table columns, empty placeholders are generated to fill the remaining columns.

Multiple cell types are supported for pdf tables:
– string cells (PdfFlowTableStringCell) – they are used to display string content. Strings are displayed on a single line by default unless the Multiline property is set to true.
– image cells (PdfFlowTableImageCell) – they are used to display images. Depending on cell size and image size, the image can be aligned left/center/right on horizontal and top/middle/bottom on vertical.
– form XObject cells (PdfFlowTableFormXObjectCell) – they are used to display form XObjects. Depending on cell size and XObject size, the XObject can be aligned left/center/right on horizontal and top/middle/bottom on vertical.
– composite cells (PdfFlowTableCompositeCell) – they are used to combine multiple types of flow content. Their Content property is a collection of flow content objects.

All cells share a common set of properties:
Background – a brush that specifies how to fill the cell background. If the property is not set explicitly, the row’s background is used.
InnerMargins – left/right/top/bottom margins inside the cell area. Cell content is placed only inside these margins.
HorizontalAlign – alignment of cell content on horizontal. If not set, the column horizontal alignment is used.
VerticalAlign – alignment of cell content on vertical. If not set, the column vertical alignment is used.
Borders – specifies how the left/right/top/bottom borders are drawn. If the property is not set explicitly, the tables’s Border is used.
RowSpan – the number of rows the cell spans over. If the RowSpan is greater than number of available rows, then only the available rows are used.
ColSpan – the number of columns the cell spans over. If the ColSpan is greater than number of columns, then it is limited to the number of columns.

Examples:

  1. Simple 3×3 table. PdfFlowTableContent.DefaultCell is a string cell by default, and AddRowWithCells method below creates cells based on its properties.
    C#:

    PdfFlowDocument document = new PdfFlowDocument();
    PdfFlowTableContent table1 = new PdfFlowTableContent(3);
    table1.Rows.AddRowWithCells("Row 1 Cell 1", "Row 1 Cell 2", "Row 1 Cell 3");
    table1.Rows.AddRowWithCells("Row 2 Cell 1", "Row 2 Cell 2", "Row 2 Cell 3");
    table1.Rows.AddRowWithCells("Row 3 Cell 1", "Row 3 Cell 2", "Row 3 Cell 3");
    document.AddContent(table1);

    VB.NET:

    Dim document As New PdfFlowDocument()
    Dim table1 As New PdfFlowTableContent(3)
    table1.Rows.AddRowWithCells("Row 1 Cell 1", "Row 1 Cell 2", "Row 1 Cell 3")
    table1.Rows.AddRowWithCells("Row 2 Cell 1", "Row 2 Cell 2", "Row 2 Cell 3")
    table1.Rows.AddRowWithCells("Row 3 Cell 1", "Row 3 Cell 2", "Row 3 Cell 3")
    document.AddContent(table1)
  2. 3×3 table, each cell is built separately.
    C#:

    PdfFlowDocument document = new PdfFlowDocument();
    PdfFlowTableContent table2 = new PdfFlowTableContent(3);
    table2.Columns[0].HorizontalAlign = PdfGraphicAlign.Near;
    table2.Columns[1].HorizontalAlign = PdfGraphicAlign.Center;
    table2.Columns[2].HorizontalAlign = PdfGraphicAlign.Far;
    table2.Border = new PdfPen(PdfRgbColor.Black, 1);
    
    PdfFlowTableStringCell c11 = new PdfFlowTableStringCell("Row 1 Cell 1");
    PdfFlowTableStringCell c12 = new PdfFlowTableStringCell("Row 1 Cell 2");
    PdfFlowTableStringCell c13 = new PdfFlowTableStringCell("Row 1 Cell 3");
    PdfFlowTableRow row1 = table2.Rows.Add();
    row1.Cells.Add(c11);
    row1.Cells.Add(c12);
    row1.Cells.Add(c13);
    row1.MinHeight = 100;
    row1.Background = new PdfBrush(PdfRgbColor.LightGray);
    
    PdfFlowTableStringCell c21 = new PdfFlowTableStringCell("Row 2 Cell 1");
    c21.VerticalAlign = PdfGraphicAlign.Center;
    PdfFlowTableStringCell c22 = new PdfFlowTableStringCell("Row 2 Cell 2");
    c22.VerticalAlign = PdfGraphicAlign.Center;
    PdfFlowTableStringCell c23 = new PdfFlowTableStringCell("Row 2 Cell 3");
    c23.VerticalAlign = PdfGraphicAlign.Center;
    PdfFlowTableRow row2 = table2.Rows.Add();
    row2.Cells.Add(c21);
    row2.Cells.Add(c22);
    row2.Cells.Add(c23);
    row2.MinHeight = 100;
    
    PdfFlowTableStringCell c31 = new PdfFlowTableStringCell("Row 3 Cell 1");
    c31.VerticalAlign = PdfGraphicAlign.Far;
    PdfFlowTableStringCell c32 = new PdfFlowTableStringCell("Row 3 Cell 2");
    c32.VerticalAlign = PdfGraphicAlign.Far;
    PdfFlowTableStringCell c33 = new PdfFlowTableStringCell("Row 3 Cell 3");
    c33.VerticalAlign = PdfGraphicAlign.Far;
    // Override the row background.
    c33.Background = new PdfBrush(PdfRgbColor.DarkGray);
    PdfFlowTableRow row3 = table2.Rows.Add();
    row3.Cells.Add(c31);
    row3.Cells.Add(c32);
    row3.Cells.Add(c33);
    row3.MinHeight = 100;
    row3.Background = new PdfBrush(PdfRgbColor.LightGray);
    document.AddContent(table2);

    VB.NET:

    Dim document As New PdfFlowDocument()
    Dim table2 As New PdfFlowTableContent(3)
    table2.Columns(0).HorizontalAlign = PdfGraphicAlign.Near
    table2.Columns(1).HorizontalAlign = PdfGraphicAlign.Center
    table2.Columns(2).HorizontalAlign = PdfGraphicAlign.Far
    table2.Border = New PdfPen(PdfRgbColor.Black, 1)
    
    Dim c11 As New PdfFlowTableStringCell("Row 1 Cell 1")
    Dim c12 As New PdfFlowTableStringCell("Row 1 Cell 2")
    Dim c13 As New PdfFlowTableStringCell("Row 1 Cell 3")
    Dim row1 As PdfFlowTableRow = table2.Rows.Add()
    row1.Cells.Add(c11)
    row1.Cells.Add(c12)
    row1.Cells.Add(c13)
    row1.MinHeight = 100
    row1.Background = New PdfBrush(PdfRgbColor.LightGray)
    
    Dim c21 As New PdfFlowTableStringCell("Row 2 Cell 1")
    c21.VerticalAlign = PdfGraphicAlign.Center
    Dim c22 As New PdfFlowTableStringCell("Row 2 Cell 2")
    c22.VerticalAlign = PdfGraphicAlign.Center
    Dim c23 As New PdfFlowTableStringCell("Row 2 Cell 3")
    c23.VerticalAlign = PdfGraphicAlign.Center
    Dim row2 As PdfFlowTableRow = table2.Rows.Add()
    row2.Cells.Add(c21)
    row2.Cells.Add(c22)
    row2.Cells.Add(c23)
    row2.MinHeight = 100
    
    Dim c31 As New PdfFlowTableStringCell("Row 3 Cell 1")
    c31.VerticalAlign = PdfGraphicAlign.Far
    Dim c32 As New PdfFlowTableStringCell("Row 3 Cell 2")
    c32.VerticalAlign = PdfGraphicAlign.Far
    Dim c33 As New PdfFlowTableStringCell("Row 3 Cell 3")
    c33.VerticalAlign = PdfGraphicAlign.Far
    ' Override the row background.
    c33.Background = New PdfBrush(PdfRgbColor.DarkGray)
    Dim row3 As PdfFlowTableRow = table2.Rows.Add()
    row3.Cells.Add(c31)
    row3.Cells.Add(c32)
    row3.Cells.Add(c33)
    row3.MinHeight = 100
    row3.Background = New PdfBrush(PdfRgbColor.LightGray)
    document.AddContent(table2)

These samples included in XFINIUM.PDF install kit provide additional information about working with PDF tables: Invoice, SimpleTable, TableCellSpans, TableGroups.

12 thoughts on “Flow Documents – part 3 – pdf tables”

  1. Hi,

    Is it possible to setup FlowTable to keep rows together, when it would exceed current page? What I mean is when I am already in the second half of a current page and I will add new table to the document, and the new table is too tall to fit the rest of the page, I want the XFinium to automatically start new page before adding the table. Default behaviour right now is that the table itself is split at the row which still fits the page and continues with the rest of rows. I came up with 3 approaches how would this be possible:

    1. set some _property_ which would do this automatically
    2. call some _CalculateHeight()_ on the table to figure out if it would fit and start new page manually
    3. receive some _event_ when adding a table would exceed current page

    Kind regards,
    Daniel

    1. The approach #2 is available in XFINIUM.PDF library.
      You can call the GetContentHeight method on any flow content object to find its height giving as parameter the available width.
      In this way you can start a new page if the content does not fit on current page.

  2. Hi,

    I am trying to create PdfFlowTableContent with PdfFlowTableColumn array it is throwing error(System.StackOverflowException)
    Please see my below code.
    Let me know if you have any solution.
    I have workaround to resolve this issue.

    PdfFlowTableColumn[] columns = new PdfFlowTableColumn[6];
    for (int i = 0; i <6; i++)
    {
    PdfFlowTableColumn column = new PdfFlowTableColumn();
    column.Width = 18;
    column.WidthIsRelativeToTable = true;
    columns[i] = column;
    }

    PdfFlowTableContent tabl = new PdfFlowTableContent(columns);

    1. Please send us (support@xfiniumpdf.com) a sample working project that we can run and reproduce the problem and we’ll investigate it.

  3. Hi

    I am trying to create PDF using PdfFlowContent with header and footer, I am able to do.
    I am trying to create the footer with “Page 1 of n”. I couldn’t, But I am able to do only with “Page #”
    Please let me know How to do with total number of pages like “Page 1 of n”

    Thanks
    Balakrishnan Srinivasan

    1. The solution at this moment is to complete the flow document, get the underlying fixed document (GetFixedDocument method), loop through the pages and draw ‘Page 1 of n’ on each page.

  4. Hi,

    Is it possible to stack tables beside each other?
    e.g. Two tables beside each other instead of the second table going below the first table?

    1. This layout can be implemented using a “master” table with 1 row and 2 columns which will result in a left cell and a right cell. You put a table in the left cell and the other one in the right cell.

      1. Thanks!, one last question please. is it possible to have rounded edges for the borders?

      2. This feature will be available in v9.2, to be released by the beginning of August.

  5. Is there a way to get PdfFlowDocuments to support Unicode? They render in ANSI only PDF. At first I tried to use PdfUnicodeTrueTypeFont until I learned that OptionalContentProperties on PdfFixedDocument is what sets up the data to make the PDF Unicode compatible.

    1. Flow documents support Unicode through the PdfUnicodeTrueTypeFont class. Default font for flow text objects is ANSI Helvetica, but you can specify your own fonts.
      The OptionalContentProperties In PdfFixedDocument has no involvement here, it controls optional content displayed in PDF pages.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: