Table Creation Code Examples
Basic Table Creation
Simple 2x2 Table
using DocumentFormat.OpenXml.Wordprocessing;
public static Table CreateSimpleTable()
{
var table = new Table();
// Table properties
var tableProperties = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
new TableBorders(
new TopBorder { Val = BorderValues.Single, Size = 4 },
new BottomBorder { Val = BorderValues.Single, Size = 4 },
new LeftBorder { Val = BorderValues.Single, Size = 4 },
new RightBorder { Val = BorderValues.Single, Size = 4 },
new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4 },
new InsideVerticalBorder { Val = BorderValues.Single, Size = 4 }
)
);
table.AppendChild(tableProperties);
// Table grid (2 columns)
var tableGrid = new TableGrid(
new GridColumn { Width = "3000" },
new GridColumn { Width = "3000" }
);
table.AppendChild(tableGrid);
// Row 1
var row1 = new TableRow();
row1.AppendChild(new TableRowProperties(new CantSplit()));
row1.AppendChild(CreateCell("Header 1", 3000, bold: true));
row1.AppendChild(CreateCell("Header 2", 3000, bold: true));
table.AppendChild(row1);
// Row 2
var row2 = new TableRow();
row2.AppendChild(new TableRowProperties(new CantSplit()));
row2.AppendChild(CreateCell("Data 1", 3000));
row2.AppendChild(CreateCell("Data 2", 3000));
table.AppendChild(row2);
return table;
}
private static TableCell CreateCell(string text, int width, bool bold = false)
{
var cell = new TableCell();
// Cell properties
cell.AppendChild(new TableCellProperties(
new TableCellWidth { Width = width.ToString(), Type = TableWidthUnitValues.Dxa }
));
// Paragraph with text
var paragraph = new Paragraph();
var run = new Run();
if (bold)
{
run.AppendChild(new RunProperties(new Bold()));
}
run.AppendChild(new Text(text));
paragraph.AppendChild(run);
cell.AppendChild(paragraph);
return cell;
}
AppraiSys Pattern: Executive Summary Table
From SubjectPropertyInformationSubstitutor.cs:
private Table CreateExecutiveSummaryTable(SubjectProperty property)
{
var table = new Table();
// Table properties
var tableProperties = new TableProperties(
// 90% width
new TableWidth { Width = "4500", Type = TableWidthUnitValues.Pct },
// Lightning borders
new TableBorders(
new TopBorder { Val = BorderValues.Lightning2 },
new LeftBorder { Val = BorderValues.Lightning2 },
new BottomBorder { Val = BorderValues.Lightning2 },
new RightBorder { Val = BorderValues.Lightning2 },
new InsideHorizontalBorder { Val = BorderValues.Lightning2 },
new InsideVerticalBorder { Val = BorderValues.None } // No vertical borders
),
// Row can't split across pages
new TableRowProperties(new CantSplit()),
// Fixed layout
new TableLayout { Type = TableLayoutValues.Fixed },
// Center table
new TableJustification { Val = TableRowAlignmentValues.Center }
);
table.AppendChild(tableProperties);
// Grid: 2 equal columns
var tableGrid = new TableGrid(
new GridColumn { Width = "3000" },
new GridColumn { Width = "3000" }
);
table.AppendChild(tableGrid);
// Add rows
AddTableRow(table, "Property Address:", property.Address);
AddTableRow(table, "Property Type:", property.PropertyType);
AddTableRow(table, "Year Built:", property.YearBuilt?.ToString());
AddTableRow(table, "Square Footage:", property.GrossLivingArea?.ToString("N0"));
AddTableRow(table, "Lot Size:", property.LotSize?.ToString("N0") + " sq ft");
AddTableRow(table, "Appraised Value:", "$" + property.AppraisedValue?.ToString("N0"));
return table;
}
private void AddTableRow(Table table, string label, string value)
{
var row = new TableRow();
row.AppendChild(new TableRowProperties(new CantSplit()));
// Label cell (bold)
var labelCell = CreateCell(label, 3000, bold: true, alignment: JustificationValues.Right);
row.AppendChild(labelCell);
// Value cell
var valueCell = CreateCell(value ?? "", 3000, alignment: JustificationValues.Left);
row.AppendChild(valueCell);
table.AppendChild(row);
}
Advanced Cell Creation
Cell with Alignment and Formatting
private static TableCell CreateCell(
string text,
int width,
bool bold = false,
JustificationValues alignment = JustificationValues.Left,
string backgroundColor = null,
VerticalTextAlignmentValues verticalAlign = VerticalTextAlignmentValues.Top)
{
var cell = new TableCell();
// Cell properties
var cellProperties = new TableCellProperties(
new TableCellWidth { Width = width.ToString(), Type = TableWidthUnitValues.Dxa },
new TableCellVerticalAlignment { Val = verticalAlign }
);
// Background color
if (backgroundColor != null)
{
cellProperties.AppendChild(new Shading
{
Fill = backgroundColor,
Val = ShadingPatternValues.Clear
});
}
cell.AppendChild(cellProperties);
// Paragraph
var paragraph = new Paragraph();
// Paragraph properties
var paragraphProperties = new ParagraphProperties(
new Justification { Val = alignment }
);
paragraph.AppendChild(paragraphProperties);
// Run
var run = new Run();
// Run properties
if (bold)
{
var runProperties = new RunProperties(new Bold());
run.AppendChild(runProperties);
}
run.AppendChild(new Text(text));
paragraph.AppendChild(run);
cell.AppendChild(paragraph);
return cell;
}
Cell Merging
Horizontal Merge (Spanning Columns)
public static Table CreateTableWithMergedCells()
{
var table = new Table();
// Properties and grid
var tableProperties = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct }
);
table.AppendChild(tableProperties);
var tableGrid = new TableGrid(
new GridColumn { Width = "2000" },
new GridColumn { Width = "2000" },
new GridColumn { Width = "2000" }
);
table.AppendChild(tableGrid);
// Row 1: Merged header spanning all 3 columns
var row1 = new TableRow();
row1.AppendChild(new TableRowProperties(new CantSplit()));
var mergedCell = new TableCell();
mergedCell.AppendChild(new TableCellProperties(
new TableCellWidth { Width = "6000", Type = TableWidthUnitValues.Dxa },
new GridSpan { Val = 3 }, // Span 3 columns
new Shading { Fill = "CCCCCC" }
));
mergedCell.AppendChild(CreateParagraph("Merged Header", bold: true, centered: true));
row1.AppendChild(mergedCell);
table.AppendChild(row1);
// Row 2: Normal cells
var row2 = new TableRow();
row2.AppendChild(new TableRowProperties(new CantSplit()));
row2.AppendChild(CreateCell("Cell 1", 2000));
row2.AppendChild(CreateCell("Cell 2", 2000));
row2.AppendChild(CreateCell("Cell 3", 2000));
table.AppendChild(row2);
return table;
}
Vertical Merge (Spanning Rows)
public static Table CreateTableWithVerticalMerge()
{
var table = new Table();
// Properties and grid
var tableProperties = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct }
);
table.AppendChild(tableProperties);
var tableGrid = new TableGrid(
new GridColumn { Width = "2000" },
new GridColumn { Width = "4000" }
);
table.AppendChild(tableGrid);
// Row 1: Start vertical merge
var row1 = new TableRow();
row1.AppendChild(new TableRowProperties(new CantSplit()));
var cell1 = new TableCell();
cell1.AppendChild(new TableCellProperties(
new TableCellWidth { Width = "2000", Type = TableWidthUnitValues.Dxa },
new VerticalMerge { Val = MergedCellValues.Restart } // Start merge
));
cell1.AppendChild(CreateParagraph("Merged Cell", bold: true));
row1.AppendChild(cell1);
row1.AppendChild(CreateCell("Row 1 Data", 4000));
table.AppendChild(row1);
// Row 2: Continue vertical merge
var row2 = new TableRow();
row2.AppendChild(new TableRowProperties(new CantSplit()));
var cell2 = new TableCell();
cell2.AppendChild(new TableCellProperties(
new TableCellWidth { Width = "2000", Type = TableWidthUnitValues.Dxa },
new VerticalMerge { Val = MergedCellValues.Continue } // Continue merge
));
cell2.AppendChild(CreateParagraph("")); // Empty paragraph required
row2.AppendChild(cell2);
row2.AppendChild(CreateCell("Row 2 Data", 4000));
table.AppendChild(row2);
// Row 3: Continue vertical merge
var row3 = new TableRow();
row3.AppendChild(new TableRowProperties(new CantSplit()));
var cell3 = new TableCell();
cell3.AppendChild(new TableCellProperties(
new TableCellWidth { Width = "2000", Type = TableWidthUnitValues.Dxa },
new VerticalMerge { Val = MergedCellValues.Continue }
));
cell3.AppendChild(CreateParagraph(""));
row3.AppendChild(cell3);
row3.AppendChild(CreateCell("Row 3 Data", 4000));
table.AppendChild(row3);
return table;
}
Property Images Table (AppraiSys)
public static Table CreatePropertyImagesTable(List<ImageData> images, int columns = 3)
{
var table = new Table();
// Table properties
var tableProperties = new TableProperties(
new TableStyle { Val = "PropertyImagesTable" },
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
new TableJustification { Val = TableRowAlignmentValues.Center },
new TableCellSpacing { Width = "100", Type = TableWidthUnitValues.Dxa },
new TableBorders(
new TopBorder { Val = BorderValues.None },
new BottomBorder { Val = BorderValues.None },
new LeftBorder { Val = BorderValues.None },
new RightBorder { Val = BorderValues.None },
new InsideHorizontalBorder { Val = BorderValues.None },
new InsideVerticalBorder { Val = BorderValues.None }
)
);
table.AppendChild(tableProperties);
// Grid
var columnWidth = 5000 / columns;
var tableGrid = new TableGrid();
for (int i = 0; i < columns; i++)
{
tableGrid.AppendChild(new GridColumn { Width = columnWidth.ToString() });
}
table.AppendChild(tableGrid);
// Add rows
int imageIndex = 0;
while (imageIndex < images.Count)
{
var row = new TableRow();
row.AppendChild(new TableRowProperties(new CantSplit()));
for (int col = 0; col < columns; col++)
{
if (imageIndex < images.Count)
{
var imageCell = CreateImageCell(images[imageIndex], columnWidth);
row.AppendChild(imageCell);
imageIndex++;
}
else
{
// Empty cell
row.AppendChild(CreateCell("", columnWidth));
}
}
table.AppendChild(row);
}
return table;
}
private static TableCell CreateImageCell(ImageData imageData, int width)
{
var cell = new TableCell();
cell.AppendChild(new TableCellProperties(
new TableCellWidth { Width = width.ToString(), Type = TableWidthUnitValues.Dxa },
new TableCellVerticalAlignment { Val = TableVerticalAlignmentValues.Top }
));
// Add image paragraph
var paragraph = new Paragraph();
paragraph.AppendChild(new ParagraphProperties(
new Justification { Val = JustificationValues.Center }
));
// TODO: Add actual image drawing element here
// (See Image Handling section)
cell.AppendChild(paragraph);
// Caption paragraph
if (!string.IsNullOrEmpty(imageData.Caption))
{
var captionParagraph = new Paragraph();
captionParagraph.AppendChild(new ParagraphProperties(
new Justification { Val = JustificationValues.Center }
));
var run = new Run();
run.AppendChild(new RunProperties(
new FontSize { Val = "18" }, // 9pt
new Italic()
));
run.AppendChild(new Text(imageData.Caption));
captionParagraph.AppendChild(run);
cell.AppendChild(captionParagraph);
}
return cell;
}
Table with Custom Borders
public static Table CreateCustomBorderTable()
{
var table = new Table();
var tableProperties = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
new TableBorders(
// Thick top border
new TopBorder
{
Val = BorderValues.Single,
Size = 24, // 3pt
Color = "000000"
},
// Thin side borders
new LeftBorder
{
Val = BorderValues.Single,
Size = 4, // 0.5pt
Color = "CCCCCC"
},
new RightBorder
{
Val = BorderValues.Single,
Size = 4,
Color = "CCCCCC"
},
// Thick bottom border
new BottomBorder
{
Val = BorderValues.Single,
Size = 24,
Color = "000000"
},
// Dotted inside horizontal
new InsideHorizontalBorder
{
Val = BorderValues.Dotted,
Size = 4,
Color = "CCCCCC"
},
// No inside vertical
new InsideVerticalBorder { Val = BorderValues.None }
)
);
table.AppendChild(tableProperties);
// Add grid and rows...
return table;
}
Dynamic Table Generation
Create Table from Data
public static Table CreateTableFromData<T>(
List<T> data,
Dictionary<string, Func<T, string>> columns,
bool headerRow = true)
{
var table = new Table();
// Properties
var tableProperties = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
new TableBorders(
new TopBorder { Val = BorderValues.Single, Size = 4 },
new BottomBorder { Val = BorderValues.Single, Size = 4 },
new LeftBorder { Val = BorderValues.Single, Size = 4 },
new RightBorder { Val = BorderValues.Single, Size = 4 },
new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4 },
new InsideVerticalBorder { Val = BorderValues.Single, Size = 4 }
)
);
table.AppendChild(tableProperties);
// Grid
int columnCount = columns.Count;
int columnWidth = 5000 / columnCount;
var tableGrid = new TableGrid();
for (int i = 0; i < columnCount; i++)
{
tableGrid.AppendChild(new GridColumn { Width = columnWidth.ToString() });
}
table.AppendChild(tableGrid);
// Header row
if (headerRow)
{
var headerRow = new TableRow();
headerRow.AppendChild(new TableRowProperties(new CantSplit()));
foreach (var column in columns.Keys)
{
var cell = CreateCell(
column,
columnWidth,
bold: true,
backgroundColor: "CCCCCC",
alignment: JustificationValues.Center
);
headerRow.AppendChild(cell);
}
table.AppendChild(headerRow);
}
// Data rows
foreach (var item in data)
{
var dataRow = new TableRow();
dataRow.AppendChild(new TableRowProperties(new CantSplit()));
foreach (var columnFunc in columns.Values)
{
var value = columnFunc(item);
var cell = CreateCell(value, columnWidth);
dataRow.AppendChild(cell);
}
table.AppendChild(dataRow);
}
return table;
}
// Usage:
var comparables = GetComparableProperties();
var table = CreateTableFromData(
comparables,
new Dictionary<string, Func<Comparable, string>>
{
{ "Address", c => c.Address },
{ "Price", c => "$" + c.Price.ToString("N0") },
{ "Sq Ft", c => c.SquareFeet.ToString("N0") },
{ "Beds", c => c.Bedrooms.ToString() },
{ "Baths", c => c.Bathrooms.ToString("F1") }
}
);
Nested Tables
Table Inside Table Cell
public static Table CreateNestedTable()
{
var outerTable = new Table();
// Outer table properties
var outerTableProps = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct }
);
outerTable.AppendChild(outerTableProps);
var outerGrid = new TableGrid(
new GridColumn { Width = "5000" }
);
outerTable.AppendChild(outerGrid);
// Outer row
var outerRow = new TableRow();
outerRow.AppendChild(new TableRowProperties(new CantSplit()));
var outerCell = new TableCell();
outerCell.AppendChild(new TableCellProperties(
new TableCellWidth { Width = "5000", Type = TableWidthUnitValues.Dxa }
));
// Header paragraph
var headerPara = new Paragraph();
var headerRun = new Run();
headerRun.AppendChild(new RunProperties(new Bold()));
headerRun.AppendChild(new Text("Container"));
headerPara.AppendChild(headerRun);
outerCell.AppendChild(headerPara);
// *** NESTED TABLE ***
var innerTable = new Table();
var innerTableProps = new TableProperties(
new TableWidth { Width = "4500", Type = TableWidthUnitValues.Dxa }
);
innerTable.AppendChild(innerTableProps);
var innerGrid = new TableGrid(
new GridColumn { Width = "2250" },
new GridColumn { Width = "2250" }
);
innerTable.AppendChild(innerGrid);
// Inner row
var innerRow = new TableRow();
innerRow.AppendChild(new TableRowProperties(new CantSplit()));
innerRow.AppendChild(CreateCell("Nested 1", 2250));
innerRow.AppendChild(CreateCell("Nested 2", 2250));
innerTable.AppendChild(innerRow);
// Add nested table to outer cell
outerCell.AppendChild(innerTable);
outerRow.AppendChild(outerCell);
outerTable.AppendChild(outerRow);
return outerTable;
}
Helper Methods
Create Paragraph
private static Paragraph CreateParagraph(
string text,
bool bold = false,
bool centered = false)
{
var paragraph = new Paragraph();
if (centered)
{
paragraph.AppendChild(new ParagraphProperties(
new Justification { Val = JustificationValues.Center }
));
}
var run = new Run();
if (bold)
{
run.AppendChild(new RunProperties(new Bold()));
}
run.AppendChild(new Text(text));
paragraph.AppendChild(run);
return paragraph;
}
Complete Example: Comparables Table
public static Table CreateComparablesTable(
SubjectProperty subject,
List<Comparable> comparables)
{
var table = new Table();
// Properties
var tableProperties = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
new TableBorders(
new TopBorder { Val = BorderValues.Single, Size = 4 },
new BottomBorder { Val = BorderValues.Single, Size = 4 },
new LeftBorder { Val = BorderValues.Single, Size = 4 },
new RightBorder { Val = BorderValues.Single, Size = 4 },
new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4 },
new InsideVerticalBorder { Val = BorderValues.Single, Size = 4 }
),
new TableLayout { Type = TableLayoutValues.Fixed }
);
table.AppendChild(tableProperties);
// Grid: Subject + 3 comparables
var tableGrid = new TableGrid(
new GridColumn { Width = "2000" }, // Field name
new GridColumn { Width = "1500" }, // Subject
new GridColumn { Width = "1000" }, // Comp 1
new GridColumn { Width = "1000" }, // Comp 2
new GridColumn { Width = "1000" } // Comp 3
);
table.AppendChild(tableGrid);
// Header row
AddHeaderRow(table, comparables.Count);
// Data rows
AddFieldRow(table, "Address",
subject.Address,
comparables.Select(c => c.Address).ToArray());
AddFieldRow(table, "Sale Price",
"$" + subject.AppraisedValue?.ToString("N0"),
comparables.Select(c => "$" + c.SalePrice.ToString("N0")).ToArray());
AddFieldRow(table, "Square Feet",
subject.GrossLivingArea?.ToString("N0"),
comparables.Select(c => c.SquareFeet.ToString("N0")).ToArray());
AddFieldRow(table, "Bedrooms",
subject.Bedrooms?.ToString(),
comparables.Select(c => c.Bedrooms.ToString()).ToArray());
AddFieldRow(table, "Bathrooms",
subject.Bathrooms?.ToString("F1"),
comparables.Select(c => c.Bathrooms.ToString("F1")).ToArray());
return table;
}
private static void AddHeaderRow(Table table, int comparableCount)
{
var row = new TableRow();
row.AppendChild(new TableRowProperties(new CantSplit()));
row.AppendChild(CreateCell("Item", 2000, bold: true,
backgroundColor: "CCCCCC", alignment: JustificationValues.Center));
row.AppendChild(CreateCell("Subject", 1500, bold: true,
backgroundColor: "CCCCCC", alignment: JustificationValues.Center));
for (int i = 0; i < comparableCount; i++)
{
row.AppendChild(CreateCell($"Comp {i + 1}", 1000, bold: true,
backgroundColor: "CCCCCC", alignment: JustificationValues.Center));
}
table.AppendChild(row);
}
private static void AddFieldRow(Table table, string fieldName,
string subjectValue, params string[] comparableValues)
{
var row = new TableRow();
row.AppendChild(new TableRowProperties(new CantSplit()));
row.AppendChild(CreateCell(fieldName, 2000, bold: true,
alignment: JustificationValues.Right));
row.AppendChild(CreateCell(subjectValue ?? "", 1500,
alignment: JustificationValues.Center));
foreach (var value in comparableValues)
{
row.AppendChild(CreateCell(value ?? "", 1000,
alignment: JustificationValues.Center));
}
table.AppendChild(row);
}
Next Steps
➡️ Next: Image Handling
Related:
- Tables in OOXML - Comprehensive table guide
- AppraiSys Patterns - More examples
- Common Fatal Mistakes - Avoid table errors
💡 Remember: Every table cell must contain at least one paragraph. Always use CantSplit() for professional-looking tables!