DEV Community

Allen Yang
Allen Yang

Posted on

C# for Office Automation: Building Professional and Nested Word Tables

In modern office automation, Word documents remain a crucial medium for presenting information and exporting data. Whether it’s monthly reports, client contracts, or internal summaries, tables are an indispensable component. Creating tables manually is not only inefficient but also prone to errors. With C# programming, we can easily automate the creation, formatting, and manipulation of Word tables.

This article provides a systematic guide on how to use Free Spire.Doc for .NET to work with Word tables, including applying table styles, dynamically adding or removing rows and columns, and inserting nested tables within a cell. With these techniques, you can quickly generate high-quality documents tailored to business needs.

Install Free Spire.Doc for .NET: Install-Package FreeSpire.Doc


1. Object Model for Working with Word Tables in C

Before manipulating tables, it is essential to understand the object structure of a Word document:

  • Document: The root object of a Word file
  • Section: Each document section may contain multiple paragraphs or tables
  • Table: The table object
  • TableRow: A row within the table
  • TableCell: A cell within a row
  • Paragraph: A paragraph inside a cell or in the main document
  • TextRange: The actual text within a paragraph
  • ParagraphStyle: A paragraph style that controls font, size, alignment, etc.

Understanding these hierarchical relationships enables flexible control over a table’s content and formatting.


2. Creating and Formatting a Table

In many business scenarios, tables need to present data clearly while maintaining a professional appearance. The following example demonstrates how to create a sales table, set column widths, adjust row height, apply background colors, and configure font styles.

using Spire.Doc;
using Spire.Doc.Documents;
using Spire.Doc.Fields;
using System.Drawing;

public class WordTableDemo
{
    public static void CreateFormattedTable(string filePath)
    {
        Document doc = new Document();
        Section sec = doc.AddSection();

        // Add title
        Paragraph title = sec.AddParagraph();
        TextRange tr = title.AppendText("2025 Product Sales Statistics");
        tr.CharacterFormat.FontName = "Calibri";
        tr.CharacterFormat.FontSize = 18;
        tr.CharacterFormat.Bold = true;
        title.Format.HorizontalAlignment = HorizontalAlignment.Center;

        sec.AddParagraph().AppendText("\n"); // spacing

        // Create table
        Table table = sec.AddTable();
        table.ResetCells(5, 4); // 5 rows, 4 columns
        table.TableFormat.Borders.BorderType = BorderStyle.Single;
        table.TableFormat.Borders.LineWidth = 1f;
        table.TableFormat.Borders.Color = Color.DarkGray;

        // Set column widths
        int[] colWidths = { 80, 200, 100, 120 };
        foreach (TableRow row in table.Rows)
        {
            for (int i = 0; i < colWidths.Length; i++)
                row.Cells[i].SetCellWidth(colWidths[i], CellWidthType.Point);
        }

        // Header style
        ParagraphStyle headerStyle = doc.AddParagraphStyle("headerStyle");
        headerStyle.CharacterFormat.Bold = true;
        headerStyle.CharacterFormat.FontName = "Calibri";
        headerStyle.CharacterFormat.FontSize = 13;
        headerStyle.ParagraphFormat.HorizontalAlignment = HorizontalAlignment.Center;

        string[] headers = { "Product ID", "Product Name", "Quantity Sold", "Sales Amount" };
        for (int i = 0; i < headers.Length; i++)
        {
            TableCell cell = table.Rows[0].Cells[i];
            cell.CellFormat.BackColor = Color.LightSteelBlue;
            cell.CellFormat.VerticalAlignment = VerticalAlignment.Middle;
            Paragraph p = cell.AddParagraph();
            p.AppendText(headers[i]);
            p.ApplyStyle(headerStyle.Name);
        }

        // Data style
        ParagraphStyle dataStyle = doc.AddParagraphStyle("dataStyle");
        dataStyle.CharacterFormat.FontName = "Calibri";
        dataStyle.CharacterFormat.FontSize = 12;
        dataStyle.ParagraphFormat.HorizontalAlignment = HorizontalAlignment.Center;

        string[,] data = {
            { "A101", "Ultra-thin Laptop", "120", "180000" },
            { "B202", "Smartphone", "450", "540000" },
            { "C303", "Wireless Earbuds", "300", "90000" },
            { "D404", "Smartwatch", "200", "80000" }
        };

        for (int r = 0; r < data.GetLength(0); r++)
        {
            for (int c = 0; c < data.GetLength(1); c++)
            {
                TableCell cell = table.Rows[r + 1].Cells[c];
                Paragraph p = cell.AddParagraph();
                p.AppendText(data[r, c]);
                p.ApplyStyle(dataStyle.Name);
                cell.CellFormat.VerticalAlignment = VerticalAlignment.Middle;
            }
        }

        doc.SaveToFile(filePath, FileFormat.Docx);
        Console.WriteLine($"Document generated: {filePath}");
    }

    static void Main(string[] args)
    {
        CreateFormattedTable("FormattedTable.docx");
    }
}
Enter fullscreen mode Exit fullscreen mode

This example demonstrates how to create a formatted table, configure column widths, row heights, background colors, and apply consistent font styling.

Preview of Output


3. Dynamically Adding and Removing Rows and Columns

In real-world applications, the number of table rows or columns often varies depending on the data. Here are some utility methods:

// Add a new row
public static void AddRow(Table table, string[] rowData)
{
    TableRow newRow = table.AddRow();
    newRow.Height = 22;
    newRow.HeightType = TableRowHeightType.Auto;

    for (int i = 0; i < rowData.Length; i++)
    {
        TableCell cell = newRow.Cells[i];
        Paragraph p = cell.AddParagraph();
        p.AppendText(rowData[i]);
        p.Format.HorizontalAlignment = HorizontalAlignment.Center;
        cell.CellFormat.VerticalAlignment = VerticalAlignment.Middle;
    }
}

// Remove a row
public static void RemoveRow(Table table, int rowIndex)
{
    if (rowIndex >= 0 && rowIndex < table.Rows.Count)
        table.Rows.RemoveAt(rowIndex);
}

// Add a column
public static void AddColumn(Table table, int colIndex, string[] colData)
{
    for (int r = 0; r < table.Rows.Count; r++)
    {
        TableCell newCell = new TableCell(table.Document);
        table.Rows[r].Cells.Insert(colIndex, newCell);
        Paragraph p = newCell.AddParagraph();
        if (r < colData.Length) p.AppendText(colData[r]);
        p.Format.HorizontalAlignment = HorizontalAlignment.Center;
        newCell.CellFormat.VerticalAlignment = VerticalAlignment.Middle;
    }
}

// Remove a column
public static void RemoveColumn(Table table, int colIndex)
{
    for (int r = 0; r < table.Rows.Count; r++)
    {
        if (colIndex >= 0 && colIndex < table.Rows[r].Cells.Count)
            table.Rows[r].Cells.RemoveAt(colIndex);
    }
}
Enter fullscreen mode Exit fullscreen mode

With these methods, a table can dynamically expand or shrink based on real-time data—ideal for reports and summary documents.


4. Nested Tables Inside a Cell

In contracts, surveys, or complex layouts, you may need to insert a table within a single cell:

using Spire.Doc;
using Spire.Doc.Documents;

public class WordTableDemo
{
    public static void InsertNestedTable(string filePath)
    {
        Document doc = new Document();
        Section sec = doc.AddSection();

        sec.AddParagraph().AppendText("Nested Table Example").CharacterFormat.FontSize = 16;
        sec.AddParagraph().AppendText("\n");

        Table outer = sec.AddTable();
        outer.ResetCells(2, 2);
        outer.TableFormat.Borders.BorderType = BorderStyle.Single;

        outer.Rows[0].Cells[0].AddParagraph().AppendText("Outer Table (0,0)");

        TableCell nestedCell = outer.Rows[0].Cells[1];
        nestedCell.AddParagraph().AppendText("Inner table below:");

        Table inner = nestedCell.AddTable();
        inner.ResetCells(3, 2);
        inner.TableFormat.Borders.BorderType = BorderStyle.Dot;

        string[,] innerData = {
            { "ID", "Name" },
            { "001", "Laptop" },
            { "002", "Phone" }
        };

        for (int r = 0; r < innerData.GetLength(0); r++)
        {
            for (int c = 0; c < innerData.GetLength(1); c++)
            {
                TableCell cell = inner.Rows[r].Cells[c];
                cell.AddParagraph().AppendText(innerData[r, c]);
                cell.CellFormat.VerticalAlignment = VerticalAlignment.Middle;
                cell.Paragraphs[0].Format.HorizontalAlignment = HorizontalAlignment.Center;
            }
        }

        outer.Rows[1].Cells[0].AddParagraph().AppendText("Outer Table (1,0)");
        outer.Rows[1].Cells[1].AddParagraph().AppendText("Outer Table (1,1)");

        doc.SaveToFile(filePath, FileFormat.Docx);
        Console.WriteLine($"Nested table document generated: {filePath}");
    }

    static void Main(string[] args)
    {
        InsertNestedTable("NestedTable.docx");
    }
}
Enter fullscreen mode Exit fullscreen mode

Nested tables are useful for displaying multi-level information within a single cell, such as clause numbers with descriptions or grouped statistical data.

Preview of Output


5. Conclusion

This article demonstrated several techniques for working with Word tables in C# using Free Spire.Doc for .NET:

  1. Creating formatted tables with consistent column widths, row heights, background colors, and font styles
  2. Dynamically adding or removing rows and columns to accommodate changing data
  3. Inserting nested tables for more advanced document layouts

With these techniques, developers can easily generate professional Word reports, contracts, or summary documents. Combined with other Spire.Doc APIs, you can further extend functionality such as inserting images, controlling pagination, or exporting to PDF—making document generation smarter and more automated.

Top comments (0)