在报表、合同、统计清单这类办公文档里,表格往往决定了信息是否清晰、输出是否规范。手工在 Word 里逐项调整不仅慢,而且一旦数据量变化,维护成本会迅速上升。本文以 Free Spire.Doc for .NET 为例,按“先理解对象模型,再完成格式化表格,最后处理动态结构和复杂布局”的顺序展开,帮助你判断它是否适合自己的文档生成场景,以及这些 API 分别该用在什么地方。
安装 Free Spire.Doc for .NET:
Install-Package FreeSpire.Doc
先理解 Word 表格的对象模型
在开始写代码前,先把 Word 文档里的对象层级理清楚,后面无论是设置样式、插入内容,还是操作某一行某一列,都会更顺手。
- Document:整个 Word 文档对象
- Section:文档分节,一个 Section 里可以放段落、表格等内容
- Table:表格对象
- TableRow:表格中的行
- TableCell:表格中的单元格
- Paragraph:正文或单元格里的段落
- TextRange:段落中的实际文本内容
- ParagraphStyle:段落样式,用来统一字体、字号、对齐方式等设置
如果把它看成一棵结构树,通常就是 Document -> Section -> Table -> TableRow -> TableCell -> Paragraph -> TextRange。理解这个结构后,你就能知道样式该挂在哪一层、内容应该追加到哪里,也更容易避免在单元格内重复创建格式配置。
如何创建并格式化一个可直接交付的表格
很多业务表格并不只是“把数据放进去”这么简单,还要兼顾标题、列宽、边框、表头底色、文本对齐等细节。下面这段代码展示了一个完整的销售统计表示例,包含从文档创建到表格填充的主要过程。

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();
// 添加标题
Paragraph title = sec.AddParagraph();
TextRange tr = title.AppendText("2025年度产品销售统计");
tr.CharacterFormat.FontName = "Yu Gothic UI";
tr.CharacterFormat.FontSize = 18;
tr.CharacterFormat.Bold = true;
title.Format.HorizontalAlignment = HorizontalAlignment.Center;
sec.AddParagraph().AppendText("n"); // 间距
// 创建表格
Table table = sec.AddTable();
table.ResetCells(5, 4); // 5行4列
table.TableFormat.Borders.BorderType = BorderStyle.Single;
table.TableFormat.Borders.LineWidth = 1f;
table.TableFormat.Borders.Color = Color.DarkGray;
// 设置列宽
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);
}
// 表头样式
ParagraphStyle headerStyle = doc.AddParagraphStyle("headerStyle");
headerStyle.CharacterFormat.Bold = true;
headerStyle.CharacterFormat.FontName = "Yu Gothic UI";
headerStyle.CharacterFormat.FontSize = 13;
headerStyle.ParagraphFormat.HorizontalAlignment = HorizontalAlignment.Center;
string[] headers = { "产品编号", "产品名称", "销售数量", "销售金额" };
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);
}
// 数据样式
ParagraphStyle dataStyle = doc.AddParagraphStyle("dataStyle");
dataStyle.CharacterFormat.FontName = "Yu Gothic UI";
dataStyle.CharacterFormat.FontSize = 12;
dataStyle.ParagraphFormat.HorizontalAlignment = HorizontalAlignment.Center;
string[,] data = {
{ "A101", "超薄笔记本", "120", "180000" },
{ "B202", "智能手机", "450", "540000" },
{ "C303", "无线耳机", "300", "90000" },
{ "D404", "智能手表", "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.Sa veToFile(filePath, FileFormat.Docx);
Console.WriteLine($"文档已生成:{filePath}");
}
}
这段示例的重点,不只是能生成一个 5 行 4 列的表格,而是把常见的格式化动作集中做完:
标题和正文区域分开处理
标题通过 Paragraph 和 TextRange 单独设置字体、字号与加粗,再用 HorizontalAlignment.Center 居中。这样做的好处是,表格本身只负责数据展示,文档结构也更清晰。

先定表格骨架,再做样式铺设
table.ResetCells(5, 4) 先创建固定的 5 行 4 列结构,随后统一设置边框样式、线宽和颜色。对于报表类文档,这种“先搭框架、后填内容”的方式更容易维护。

列宽和样式尽量统一配置
示例通过 int[] colWidths = { 80, 200, 100, 120 }; 给四列分别指定宽度,再循环写入每一行。这种做法适合列含义固定的业务表格,比如“编号、名称、数量、金额”这类结构明确的数据。
另外,表头和数据区分别定义 headerStyle 与 dataStyle,比在每个单元格里逐项设置字体更稳妥。后续如果要整体换字体、调整字号或对齐方式,也只需要改样式定义。
适合哪些场景
这种创建方式适合结构比较稳定的 Word 输出任务,例如销售统计、库存清单、日报周报、客户列表等。只要列数基本固定,就可以通过数组或数据库结果集把内容批量填入表格,生成速度和一致性都会比手工排版高得多。
数据量不固定时,怎样动态添加或删除行列
真实业务里,表格行数通常不会提前写死,甚至列也可能根据配置变化。这时就不能只靠一次 ResetCells 解决问题,还需要对行列进行增删。
// 添加新行
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;
}
}
// 删除行
public static void RemoveRow(Table table, int rowIndex)
{
if (rowIndex >= 0 && rowIndex < table.Rows.Count)
table.Rows.RemoveAt(rowIndex);
}
// 添加列
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;
}
}
// 删除列
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);
}
}
这里可以把四个方法分成两组来看:行操作和列操作。
添加、删除行:适合明细持续增长的表格
AddRow 用 table.AddRow() 新增一行,然后按照传入的 rowData 逐个写入单元格内容,并补上水平居中和垂直居中的格式。这类方法很适合订单明细、流水记录、库存条目等“记录条数不固定”的场景。
RemoveRow 则通过索引判断后调用 table.Rows.RemoveAt(rowIndex) 删除指定行。索引边界判断虽然简单,但在批量处理数据时非常关键,否则很容易因为下标越界直接抛异常。
添加、删除列:适合报表字段按配置变化
AddColumn 的处理方式是遍历所有行,在每一行的指定位置插入一个新的 TableCell。这样可以确保整张表格都同步增加一列,而不是只改某一行导致结构错位。
这里有一个细节值得注意:新增列时使用的是 new TableCell(table.Document),说明单元格对象需要绑定到当前文档上下文里。随后再用 Cells.Insert(colIndex, newCell) 把它插入到目标位置,并根据 colData 按行填值。
RemoveColumn 的思路与之对应,遍历每一行后删除相同列索引处的单元格。只要索引校验做对,整张表就能保持一致。
动态表格更适合哪些业务
如果你的数据来自数据库查询、接口返回或用户勾选字段,表格结构往往不是固定的。此时,把“表格模板”和“增删逻辑”拆开会更好维护:基础样式负责整体观感,行列操作负责适配不同数据规模。对报表系统、审批单、导出清单来说,这种方式会比提前写死所有单元格更灵活。
复杂文档里,什么时候该用单元格嵌套表格
有些 Word 文档不是简单的二维数据展示,而是需要在一个大单元格内部继续承载子结构,例如合同条款的子项说明、问卷题目的附加选项、分区统计的局部明细等。这个时候,单元格内嵌套表格会比纯文本换行更清晰。
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("嵌套表格示例").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("外表格 (0,0)");
TableCell nestedCell = outer.Rows[0].Cells[1];
nestedCell.AddParagraph().AppendText("内部表格如下:");
Table inner = nestedCell.AddTable();
inner.ResetCells(3, 2);
inner.TableFormat.Borders.BorderType = BorderStyle.Dot;
string[,] innerData = {
{ "编号", "名称" },
{ "001", "笔记本" },
{ "002", "手机" }
};
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("外表格 (1,0)");
outer.Rows[1].Cells[1].AddParagraph().AppendText("外表格 (1,1)");
doc.Sa veToFile(filePath, FileFormat.Docx);
Console.WriteLine($"嵌套表格文档已生成:{filePath}");
}
static void Main(string[] args)
{
InsertNestedTable("NestedTable.docx");
}
}
这段代码的关键点在于,先创建一个外层表格 outer,再选中其中一个单元格 nestedCell,随后直接在该单元格里调用 AddTable() 创建内层表格 inner。
外层表格负责布局,内层表格负责明细
外层表格用 outer.ResetCells(2, 2) 构建基础布局,边框样式为 BorderStyle.Single。其中一个单元格作为承载区域,先追加说明文字“内部表格如下:”,再放入真正的子表。
这种结构很适合把“概览”和“细项”放在同一个区域内。例如左侧放条款标题,右侧放条款细目;或者上层单元格放统计分类,下层嵌套表放分类下的具体数据。
内层表格可以独立定义自己的结构和边框
内层表格通过 inner.ResetCells(3, 2) 创建 3 行 2 列,并把边框设为 BorderStyle.Dot。这说明嵌套表格并不是“继承外表格的一部分样式就结束了”,它本身仍然是完整的 Table 对象,可以单独设置边框、对齐和内容。
在示例里,innerData 数组中包含“编号、名称”以及两条明细数据,循环写入时继续设置垂直居中和段落居中。也就是说,嵌套后并不会失去常规表格的控制能力。
哪些文档值得用嵌套表格
如果只是简单的文本说明,直接段落换行通常已经够用;但当一个单元格里需要再表现一组有行列关系的数据时,嵌套表格更合适。常见场景包括合同附件项、问卷结果块、项目拆分清单、带子分类的统计表等。它的优势不在“更炫”,而在于层级更清楚,后续修改也更可控。
这套做法能解决哪些 Word 生成需求
综合来看,使用 C# 配合 Free Spire.Doc for .NET 处理 Word 表格,至少可以覆盖三类高频需求:
- 创建格式化表格,并统一设置列宽、行高、背景色和字体样式
- 动态添加或删除行列,适配数据量和字段结构变化
- 在单元格内嵌套表格,处理更复杂的排版和分层展示
如果你的目标是自动生成报表、合同、汇总文档或导出清单,这些能力已经能覆盖大部分核心环节。进一步结合 Free Spire.Doc 的其他 API,还可以继续扩展图片插入、分页控制、PDF 导出等功能,把原本依赖人工排版的 Word 输出流程改造成可复用的程序化方案。













