Search code examples
openxmlmultilinecontentcontrol

Insert multiple lines of text into a Rich Text content control with OpenXML


I'm having difficulty getting a content control to follow multi-line formatting. It seems to interpret everything I'm giving it literally. I am new to OpenXML and I feel like I must be missing something simple.

I am converting my multi-line string using this function.

    private static void parseTextForOpenXML(Run run, string text)
    {
        string[] newLineArray = { Environment.NewLine, "<br/>", "<br />", "\r\n" };
        string[] textArray = text.Split(newLineArray, StringSplitOptions.None);

        bool first = true;

        foreach (string line in textArray)
        {
            if (!first)
            {
                run.Append(new Break());
            }

            first = false;

            Text txt = new Text { Text = line };
            run.Append(txt);
        }
    }

I insert it into the control with this

    public static WordprocessingDocument InsertText(this WordprocessingDocument doc, string contentControlTag, string text)
    {
        SdtElement element = doc.MainDocumentPart.Document.Body.Descendants<SdtElement>().FirstOrDefault(sdt => sdt.SdtProperties.GetFirstChild<Tag>().Val == contentControlTag);

        if (element == null)
            throw new ArgumentException("ContentControlTag " + contentControlTag + " doesn't exist.");

        element.Descendants<Text>().First().Text = text;
        element.Descendants<Text>().Skip(1).ToList().ForEach(t => t.Remove());

        return doc;
    }

I call it with something like...

doc.InsertText("Primary", primaryRun.InnerText);

Although I've tried InnerXML and OuterXML as well. The results look something like

Example AttnExample CompanyExample AddressNew York, NY 12345 or

<w:r xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:t>Example Attn</w:t><w:br /><w:t>Example Company</w:t><w:br /><w:t>Example Address</w:t><w:br /><w:t>New York, NY 12345</w:t></w:r>

The method works fine for simple text insertion. It's just when I need it to interpret the XML that it doesn't work for me.

I feel like I must be super close to getting what I need, but my fiddling is getting me nowhere. Any thoughts? Thank you.


Solution

  • I believe the way I was trying to do it was doomed to fail. Setting the Text attribute of an element is always going to be interpreted as text to be displayed it seems. I ended up having to take a slightly different tack. I created a new insert method.

        public static WordprocessingDocument InsertText(this WordprocessingDocument doc, string contentControlTag, Paragraph paragraph)
        {
            SdtElement element = doc.MainDocumentPart.Document.Body.Descendants<SdtElement>().FirstOrDefault(sdt => sdt.SdtProperties.GetFirstChild<Tag>().Val == contentControlTag);
    
            if (element == null)
                throw new ArgumentException("ContentControlTag " + contentControlTag + " doesn't exist.");
    
            OpenXmlElement cc = element.Descendants<Text>().First().Parent;
            cc.RemoveAllChildren();
            cc.Append(paragraph);
    
            return doc;
        }
    

    It starts the same, and gets the Content Control by searching for it's Tag. But then I get it's parent, remove the Content Control elements that were there and just replace them with a paragraph element.

    It's not exactly what I had envisioned, but it seems to work for my needs.