我正在使用OpenXml实用程序将内容动态添加到Word文档中,然后我想更新目录。
var byteTempArray = File.ReadAllBytes("Sample.docx");
var _memoryStream = new MemoryStream();
_memoryStream.Write(byteTempArray, 0, byteTempArray.Length);
var _wordprocessingDocument = WordprocessingDocument.Open(_memoryStream, true);
var bodyDoc = _wordprocessingDocument.MainDocumentPart.Document.Body;
SimpleField f = new SimpleField
{
Instruction = "sdtContent",
Dirty = true
};
bodyDoc.AppendChild(f);
_wordprocessingDocument.MainDocumentPart.Document.Save();
_wordprocessingDocument.Close();
File.WriteAllBytes(Guid.NewGuid()+".docx", _memoryStream.ToArray());
我已在Dirty设置为true的文档中附加了SimpleField。当我打开生成的文件时,它显示下面的确认消息以更新目录。单击是,将正确更新目录。
但是问题是错误!未定义书签。文本被附加在文档的底部。
任何想法如何通过适当的目录更新功能来删除此错误消息。
我对您要执行的操作的理解是,一旦用户使用Microsoft Word打开该文档,就会在文档中插入一个脏的w:fldSimple
元素(SimpleField
类),以使Word更新包括TOC在内的所有字段。但是,如果在更新字段后查看Microsoft Word生成的Open XML标记,您会发现w:fldSimple
是罪魁祸首。
我创建了以下代码,以生成一个(几乎)仅有一个字段的简单Word文档:
[Fact]
public void CheckBookmarkNotDefined()
{
using WordprocessingDocument wordDocument = WordprocessingDocument.Create(
"SimpleField.docx", WordprocessingDocumentType.Document);
MainDocumentPart part = wordDocument.AddMainDocumentPart();
part.Document =
new Document(
new Body(
new Paragraph(
new SimpleField
{
Instruction = "sdtContent",
Dirty = true
})));
}
以上代码在主文档部分中创建以下Open XML标记:
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<w:p>
<w:fldSimple w:instr="sdtContent" w:dirty="true" />
</w:p>
</w:body>
</w:document>
请注意,w:fldSimple
元素包含在w:p
元素(Paragraph
类)中,因为将其添加到w:body
元素(Body
类)会产生无效的Open XML标记。
[在Microsoft Word中打开该文档,更新字段并保存文档,使Word创建以下Open XML标记(我已经简化了一点):
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<w:p>
<w:r>
<w:fldChar w:fldCharType="begin"/>
</w:r>
<w:r>
<w:instrText>sdtContent</w:instrText>
</w:r>
<w:r>
<w:fldChar w:fldCharType="separate"/>
</w:r>
<w:r>
<w:rPr>
<w:b/>
<w:bCs/>
</w:rPr>
<w:t>Error! Bookmark not defined.</w:t>
</w:r>
<w:r>
<w:fldChar w:fldCharType="end"/>
</w:r>
</w:p>
<w:sectPr>
[Child elements removed for clarity]
</w:sectPr>
</w:body>
</w:document>
[您可以看到Word使用多个w:fldSimple
元素和一个以“ sdtContent”作为其内容的w:fldChar
元素将简单字段(w:instrText
元素)变成了复杂字段。此外,您可以看到文本“错误!未定义书签”。作为字段的结果。
Word创建该错误消息是因为您的指令文本("sdtContent"
)不正确。如果将"sdtContent"
替换为有效的字段名称,例如"AUTONUM"
,则不会看到该错误消息。但是,在AUTONUM
的情况下,显然会得到可见场结果。为避免这种情况,可以使用REF
字段,但是您需要一个有效的书签。在下面的示例中创建:
[Fact]
public void CreateSimpleFieldForAutomaticUpdate()
{
using WordprocessingDocument wordDocument = WordprocessingDocument.Create(
"SimpleFieldRef.docx", WordprocessingDocumentType.Document);
MainDocumentPart part = wordDocument.AddMainDocumentPart();
part.Document =
new Document(
new Body(
new Paragraph(
new Run(
new Text("Hello World!"))),
new BookmarkStart { Id = "32767", Name = "_RefUpdate" },
new BookmarkEnd { Id = "32767" },
new Paragraph(
new SimpleField
{
Instruction = "REF _RefUpdate",
Dirty = true
}),
new SectionProperties()));
}
您必须编写代码,以便在您的w:bookmarkStart
子元素之前插入一个BookmarkStart
元素(w:bookmarkEnd
类),BookmarkEnd
元素(w:p
类)和w:fldSimple
元素。 w:sectPr
元素(SectionProperties
类)。在我的示例中,我使用了一个较大的整数值作为书签ID,并使用了_RefUpdate
作为书签名称,这在Instruction
属性中也使用了。]