Search code examples
c#ms-wordopenxmlopenxml-sdk

Edit Word bookmark changes the font


I have a C# program that generates documents using OpenXml. It replaces bookmarks with values using the following method :

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);
}

In this particular word document, the font used is Raleway. There are several bookmarks and after the execution of this method, two bookmarks are using the Calibri font. I tried to rewrite theses bookmarks to be sure they are in Raleway but they continue to change to Calibri.

How is this possible ?


Solution

  • First of all your code creates new element without previous RunProperties. So, you get something like next snippet:

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

    instead of it:

    <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>  
    

    You can copy any properties like this:

    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);
    }