merger
merger

Reputation: 734

Better way of getting Font info from openxml

I'm filling out a kind of template Word file (not a .dot) with OpenXML. The problem i ran into is that when i add new text to the document uses the default font and font size of the Word document. I wanted it to use the font and size of the paragraph that i'm adding to or the format in a existing table that i'm adding to.

I found one way, but i don't think its a good way. So...is there a better way of doing it?

This is from a Paragraph

    private RunProperties GetRunPropertyFromParagraph(Paragraph paragraph)
    {
        var runProperties = new RunProperties();
        var fontname = "Calibri";
        var fontSize = "18";
        try
        {
            fontname =
                paragraph.GetFirstChild<ParagraphProperties>()
                         .GetFirstChild<ParagraphMarkRunProperties>()
                         .GetFirstChild<RunFonts>()
                         .Ascii;
        }
        catch
        {
            //swallow
        }
        try
        {
            fontSize =
                paragraph.GetFirstChild<Paragraph>()
                         .GetFirstChild<ParagraphProperties>()
                         .GetFirstChild<ParagraphMarkRunProperties>()
                         .GetFirstChild<FontSize>()
                         .Val;
        }
        catch
        {
            //swallow
        }
        runProperties.AppendChild(new RunFonts() { Ascii = fontname });
        runProperties.AppendChild(new FontSize() { Val = fontSize });
        return runProperties;
    }

And this from a TableCell

    private RunProperties GetRunPropertyFromTableCell(TableRow rowCopy, int cellIndex)
    {
        var runProperties = new RunProperties();
        var fontname = "Calibri";
        var fontSize = "18";
        try
        {
            fontname =
                rowCopy.Descendants<TableCell>()
                       .ElementAt(cellIndex)
                       .GetFirstChild<Paragraph>()
                       .GetFirstChild<ParagraphProperties>()
                       .GetFirstChild<ParagraphMarkRunProperties>()
                       .GetFirstChild<RunFonts>()
                       .Ascii;
        }
        catch
        {
            //swallow
        }
        try
        {
            fontSize =
                   rowCopy.Descendants<TableCell>()
                          .ElementAt(cellIndex)
                          .GetFirstChild<Paragraph>()
                          .GetFirstChild<ParagraphProperties>()
                          .GetFirstChild<ParagraphMarkRunProperties>()
                          .GetFirstChild<FontSize>()
                          .Val;
        }
        catch
        {
            //swallow
        }
        runProperties.AppendChild(new RunFonts() { Ascii = fontname });
        runProperties.AppendChild(new FontSize() { Val = fontSize });
        return runProperties;
    }

The code works. At least in the documents that i have tried. But it seems like a awful way of doing it, but i haven't found a better solution so if you have one please share :)

Upvotes: 1

Views: 4693

Answers (1)

Kaspar Kjeldsen
Kaspar Kjeldsen

Reputation: 992

I do it like this: When I update or replace a Run, I make sure to check when I delete the old stuff, if an element has children, and then if it has a child that is a "RunProperties". If it does, I just save those properties and add them to my new Run after I've deleted the old stuff.

Hasn't failed me yet.

var bkms = YourBookmarkStart;
OpenXmlElement elem = bkms.NextSibling();
RunProperties oldRunProperties = null;
while (elem != null && !(elem is BookmarkEnd))
{
    OpenXmlElement nextElem = elem.NextSibling();
    if (elem.HasChildren)
    {
        try
        {
             oldRunProperties = (RunProperties)elem.GetFirstChild<RunProperties>().Clone();
        }
        catch { }
    }
    if (!(elem is BookmarkStart))
        elem.Remove();
    elem = nextElem;
}

Run r = new Run(new Text(newText));
if (oldRunProperties != null) r.PrependChild<RunProperties>(oldRunProperties);
bkms.Parent.InsertAfter<Run>(r, bkms);

It should grab whatever runproperties a given paragraph has, unless it hasn't got any, in which case it won't add any, and therefore use whatever is default in your document.

Upvotes: 1

Related Questions