编辑Word书签更改字体

Edit Word bookmark changes the font

我有一个使用 OpenXml 生成文档的 C# 程序。它使用以下方法用值替换书签:

private void FillBookmark(BookmarkStart bookmark, string value)
{
    var text = new Text(value);
    bookmark.RemoveAllChildren();

    IEnumerable<OpenXmlElement> elementsAfter = bookmark.ElementsAfter();
    IEnumerable<OpenXmlElement> insideBookmark = elementsAfter.TakeWhile(element => !(element is BookmarkEnd));
    foreach (OpenXmlElement element in insideBookmark)
    {
        element.RemoveAllChildren();
    }
    OpenXmlElement previousSibling = bookmark.PreviousSibling();
    while (previousSibling is BookmarkStart || previousSibling is BookmarkEnd)
    {
        previousSibling = previousSibling.PreviousSibling();
    }
    var container = new Run(text);
    previousSibling.AppendChild(container);
}

在这个特定的word文档中,使用的字体是Raleway。有几个书签,执行此方法后,有两个书签使用的是 Calibri 字体。我试图重写这些书签以确保它们在 Raleway 中,但它们继续更改为 Calibri。

这怎么可能?

首先,您的代码创建了没有先前 RunProperties 的新元素。 所以,你会得到类似下一个片段的东西:

<w:r>
    <w:t>valuexX</w:t>
</w:r>

代替它:

<w:r w:rsidRPr="00DE66A4">
    <w:rPr>
        <w:rFonts w:ascii="Algerian" w:hAnsi="Algerian" />
            <w:lang w:val="en-US" />
    </w:rPr>
    <w:t>6</w:t>               
</w:r>  

您可以像这样复制任何属性:

private void FillBookmark(BookmarkStart bookmark, string value)
{
  var text = new Text(value);
  bookmark.RemoveAllChildren();

  IEnumerable<OpenXmlElement> elementsAfter = bookmark.ElementsAfter();
  IEnumerable<OpenXmlElement> insideBookmark = elementsAfter.TakeWhile(element => !(element is BookmarkEnd));
  foreach (OpenXmlElement element in insideBookmark)
  {
    element.RemoveAllChildren();
  }
  OpenXmlElement previousSibling = bookmark.PreviousSibling();
  while (previousSibling is BookmarkStart || previousSibling is BookmarkEnd)
  {
    previousSibling = previousSibling.PreviousSibling();
  }

  //Get previous font.
  var runProperties = previousSibling.GetFirstChild<ParagraphMarkRunProperties>().GetFirstChild<RunFonts>();
  //var runProperties = previousSibling.GetFirstChild<RunProperties>(); - if its simple element.

  // Clone.
  var newProperty = (RunFonts)runProperties.Clone();

  // Create container with properties.
  var container = new Run(text)
  {
    RunProperties = new RunProperties() { RunFonts = newProperty }
  };

  previousSibling.AppendChild(container);
}

书签有点奇怪。人们很自然地认为书签是可以包含 fx a Run 的东西,就像这样(注意:这不是有效的 OpenXML,它只是为了说明一点):

<w:bookmark>   
    <w:run>
        <w:text>Some text</w:text>
    </w:run>
</w:bookmark>

但这不是他们的工作方式。相反,它们是使用 BookmarkStartBookmarkEnd 定义的 - 使用属性 id 来匹配相应的开始 - 和 end-elements.

BookmarkStartBookmarkEnd 可以涵盖所有类型的内容 - 它们甚至不必位于同一段落中(如 this example on MSDN 所示)。

一个 word-document 有两个看起来相邻的书签可以以一种奇怪的方式嵌套。这是我刚刚拼凑的 Word-document 中的一个示例:它有一个带有两个书签的段落:b1b2。请注意 b2bookmarkStart 是 'inside' 书签 b1.

<w:p xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
    <w:r>
        <w:t>Some text with a</w:t>
    </w:r>
    <w:bookmarkStart w:name="b1" w:id="1" />
    <w:r>
        <w:t>couple</w:t>
    </w:r>
    <w:bookmarkStart w:name="b2" w:id="2" />
    <w:bookmarkEnd w:id="1" />
    <w:r>
        <w:t xml:space="preserve"> of bookmarks.</w:t>
    </w:r>
    <w:bookmarkEnd w:id="2" />
</w:p>

很难准确猜测您的示例中发生了什么,但我的猜测是 bookmarkStartbookmarkEnd 的结构与您预期的不同。

我发现在调试此类内容时使用 OpenXML Productivity Tool 很有用。

(而且 BookmarkStart 没有 children,所以不需要调用 bookmark.RemoveAllChildren