How to Work with Tables in .NET

How to Work with Tables in .NET

This guide shows how to build, format, and read tables programmatically in Aspose.Words FOSS for .NET, using the Table, Row, and Cell classes in the Aspose.Words.Tables namespace together with DocumentBuilder. It covers constructing a table from scratch, formatting cells and rows as you build, controlling table-wide layout and AutoFit, setting preferred widths, merging cells, and reading tables already present in a loaded document.

Step-by-Step Guide

Step 1: Install the Package

Aspose.Words FOSS for .NET does not yet publish a NuGet package – build the library from source instead. Clone https://github.com/aspose-words-foss/Aspose.Words-FOSS-for-.NET.git, then build Aspose.Words.sln in Release configuration with the .NET SDK and reference the resulting Aspose.Words assembly from your project. The library targets .NET Standard 2.0, so it runs on .NET Framework 4.6.2+ and .NET 6/8/10.


Step 2: Import Required Classes

Add a using Aspose.Words; directive for the core document classes (Document, DocumentBuilder), and a using Aspose.Words.Tables; directive for the table-specific classes this guide covers – Table, Row, Cell, CellFormat, RowFormat, PreferredWidth, and related enums.


Step 3: Build a New Table with DocumentBuilder

Create a Document and a DocumentBuilder bound to it, then call DocumentBuilder.StartTable() to begin a table at the cursor. For each cell in a row, call DocumentBuilder.InsertCell(), then close the row with DocumentBuilder.EndRow(). Repeat for as many rows as the table needs, and close the whole table with DocumentBuilder.EndTable(). Every StartTable() needs a matching EndTable(), and every row needs a matching EndRow(), or the builder’s internal state – and the resulting document tree – ends up malformed.


Step 4: Format Cells and Rows as You Build

Set DocumentBuilder.CellFormat and DocumentBuilder.RowFormat before calling InsertCell() or EndRow() to apply formatting to the cells and rows the builder is about to create – these two properties act as a template for new content, not a retroactive change to cells already inserted. CellFormat exposes Borders, Shading, Width, WrapText, FitText, HorizontalMerge, VerticalMerge, VerticalAlignment, PreferredWidth, and the four padding properties (LeftPadding, RightPadding, TopPadding, BottomPadding), which can all be set at once with SetPaddings(). RowFormat exposes Borders, Height, HeightRule, AllowBreakAcrossPages, and HeadingFormat. Call CellFormat.ClearFormatting() or RowFormat.ClearFormatting() to reset either one to defaults before setting new values for the next row or cell.


Step 5: Set Table-Wide Layout and AutoFit

Once the table exists, set layout properties directly on the Table object: Alignment (TableAlignment), Bidi, LeftIndent, PreferredWidth, Style, StyleIdentifier, StyleName, StyleOptions (TableStyleOptions), and TextWrapping. Call Table.SetBorders() to apply one border style, width, and color across the entire table, or Table.SetBorder() to set a single side; ClearBorders() and ClearShading() reset those. Table.AutoFit(AutoFitBehavior) resizes the table and its cells according to the chosen behavior – call it again after any structural edit, since it reflects the table’s state only at the moment it runs, not continuously.


Step 6: Set Preferred and Cell Widths

Create width values with the static factory methods PreferredWidth.FromPercent() for a layout that adapts to the available page width, or PreferredWidth.FromPoints() for a fixed width; PreferredWidthType reports which kind of value (Auto, Percent, or Points) a given PreferredWidth holds. Assign the result to either Table.PreferredWidth for the whole table or CellFormat.PreferredWidth for one cell.


Step 7: Merge Cells

Mark cells as merged by setting CellFormat.HorizontalMerge or CellFormat.VerticalMerge (both typed CellMerge) on the cells that should participate in the merge. If cells were only made to look merged by matching their widths rather than being explicitly flagged, call Table.ConvertToHorizontallyMergedCells() to convert that visual arrangement into cells with real CellMerge state. CellVerticalAlignment controls how content is justified vertically within a cell, independent of any merge.


Step 8: Read Tables from an Existing Document

To work with tables already in a loaded document, read Body.Tables (or the Tables property on any other Story) – a TableCollection – rather than building new ones. Table.Rows returns a RowCollection and Row.Cells returns a CellCollection; all three collection types support Add(), Insert(), Remove(), RemoveAt(), Contains(), and IndexOf() for programmatic edits. After removing rows or cells, call Table.EnsureMinimum(), Row.EnsureMinimum(), or Cell.EnsureMinimum() so the node keeps the minimum valid structure Word expects – an empty row, an empty cell, or an empty paragraph, respectively.

Common Issues and Fixes

A saved document looks malformed, or an error occurs while saving A row or the table itself was never closed. Always pair DocumentBuilder.StartTable() with a final EndTable(), and close every row with EndRow() before moving to the next one or ending the table.

New cells don’t pick up the formatting I set CellFormat and RowFormat were changed on the DocumentBuilder after the affected cells were already inserted. Set DocumentBuilder.CellFormat / RowFormat before the InsertCell() or EndRow() call that creates the content you want formatted.

Table doesn’t resize the way I expect after I edit its content Table.AutoFit(AutoFitBehavior) reflects the table’s structure only at the moment it is called. Call it again after any structural edit – adding or removing rows, cells, or content – if the layout needs to be re-fitted.

Cells that look merged behave as separate cells when read back The cells were only matched by width, not flagged with CellMerge. Call Table.ConvertToHorizontallyMergedCells(), or set CellFormat.HorizontalMerge / VerticalMerge explicitly on the cells that should merge.

Removing rows or cells leaves the table in an invalid state Word expects every Table, Row, and Cell to keep a minimum valid structure. After removing content programmatically, call EnsureMinimum() on the node just modified.

Frequently Asked Questions

How do I build a table from scratch instead of editing an existing one?

Use DocumentBuilder: call StartTable(), then InsertCell() for each cell in a row, EndRow() to close the row, repeat for additional rows, and EndTable() to close the table.

How do I get the tables that already exist in a loaded document?

Read the Tables property (a TableCollection) on the Body of the section you’re interested in, or on any other Story such as a header or footer.

How do I set a table to a percentage of the page width instead of a fixed width?

Assign Table.PreferredWidth = PreferredWidth.FromPercent(value) rather than PreferredWidth.FromPoints(value).

What is the difference between setting borders with SetBorders and SetBorder?

Table.SetBorders() applies one line style, width, and color to every border in the table at once; Table.SetBorder() sets a single side, letting different sides carry different formatting.

How do I reset formatting on a cell or row before reusing it?

Call CellFormat.ClearFormatting() on the cell’s CellFormat, or RowFormat.ClearFormatting() on the row’s RowFormat.

See Also