用 DocumentFormat.OpenXml 创建空白 Word 文档需调用 WordprocessingDocument.Create(),手动添加 MainDocumentPart,构造 Paragraph 时必须包含 ParagraphProperties、Run 和 Text 三层嵌套,表格须嵌入 Paragraph 内并确保 TableCell 包含 Paragraph,图片插入需匹配 ImagePartType 与文件类型且使用绝对路径,所有操作后须调用 Close() 或 using 块释放句柄。
用 DocumentFormat.OpenXml 创建空白 Word 文档,别碰 Microsoft.Office.Interop.Word
interop 本质是启动 word 进程,本地没装 office 就直接崩,服务器环境几乎不可用。openxml 是纯 .net 库,操作 zip 包里的 xml,无依赖、可部署、能批量。
安装 NuGet 包:DocumentFormat.OpenXml(注意不是 OpenXMLSDK 旧版)。
- 新建文档必须调用
WordprocessingDocument.Create(),传入文件路径和DocumentFormat.OpenXml.WordprocessingDocumentType.Document - 必须手动创建
MainDocumentPart并调用AddMainDocumentPart(),否则保存后 Word 打不开,报“文件已损坏” - 写完内容后一定要调用
document.Close()或用using块,否则文件句柄未释放,下次写入会提示“进程无法访问该文件”
插入段落和文字:别直接 new Paragraph() 就完事
OpenXML 不是“加个控件”,而是拼 XML 节点。一个段落至少要包含 ParagraphProperties + Run + Text 三层嵌套,缺一层 Word 就拒绝解析。
常见错误现象:DocumentFormat.OpenXml.OpenXmlPackageException: The element has invalid child element —— 多半是漏了 Run 或 ParagraphProperties。
- 推荐用
new Paragraph(new ParagraphProperties(), new Run(new Text("hello")))显式构造 - 如果要居中/加粗/换字体,改的是
ParagraphProperties或RunProperties,不是Text本身 -
Text构造函数里传的字符串会原样写入 XML,中文不用额外编码,但<、>、&会被自动转义,无需手动处理
表格怎么加?Table 必须嵌在 Paragraph 里,且要有 TableRow 和 TableCell
OpenXML 表格不是独立容器,它本质上是一段“特殊段落”。直接把 Table 加到 Body 下,Word 会忽略整张表。
典型结构链路:Body → Paragraph → Table → TableRow → TableCell → Paragraph → Run → Text。少任何一环都显示为空白或报错。
- 每个
TableCell必须包裹至少一个Paragraph,哪怕只放空段落也要写上 - 合并单元格靠
GridSpan(列合并)和VMerge(行合并),不是靠设置宽度;VMerge的Val值必须是VMergeValues.Restart(首行)或VMergeValues.Continue(后续行) - 表格样式(如边框)由
TableProperties控制,但默认无边框;想显示边框得显式设置TableBorders,否则导出后是“隐形表”
图片插入失败?ImagePart 和 Blip 要配对,且路径必须是绝对路径
OpenXML 不支持直接读取相对路径或流对象。你传进去的图片路径,必须是运行时能真实访问到的绝对路径(比如 C:\temp\logo.png),否则抛 FileNotFoundException。
更隐蔽的坑:图片插入后 Word 不显示,但也不报错——大概率是 ImagePart 的 ContentType 和实际文件类型不匹配(比如 PNG 用了 image/jpeg)。
- 用
document.MainDocumentPart.AddImagePart(ImagePartType.Jpeg)时,ImagePartType必须严格对应文件扩展名(Png、Jpeg、Gif) - 插入后要手动关联
Blip到ImagePart的Id,通过mainPart.GetIdOfPart(imagePart)获取,不能硬编码 - 图片尺寸控制靠
Extent(EMUs 单位),1 英寸 = 914400 EMUs;直接设像素会失真,建议先按比例换算
复杂点在于:所有部件(文本、表格、图片)的顺序和嵌套层级,本质是 XML 树结构。写错一层,轻则样式丢失,重则整个文档打不开。调试时别只看 C# 代码,用 dotnet tool install -g openxmlsdk 安装 SDK 工具,用 openxmlsdk show xxx.docx 拆包看实际 XML,比猜快得多。










