Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / productivity / Office

Add dynamic content controls to a word document

4.71/5 (6 votes)
21 Apr 2012CPOL1 min read 66.5K   2.9K  
Create dynamic content controls at run-time.

Introduction

This article tells how to add dynamic content controls to an existing Word document at run-time. I assume users have the basic knowledge of office Open XML SDK 2.0.

Code Walkthrough

  1. Create a Word document template which has two content controls.

    Open Microsoft Word. Click on 'Developer' ribbon. Then choose 'Plain text content control'.

    Image 1

    It will add a content control on the document. Click on Properties. This will open Content Properties window. Let us tag the first control as "cc1".

    Image 2

    Similarly create another control and tag it as "cc2". In design mode the two controls would look like

    Image 3

    Save the file as word template ("Doc1.dotx").
  2. Include the Doc1.dotx file in the project, right click on it and set Build action as Content & Copy to output directory as Copy if Newer,

    Image 4
  3. Create two lists that would contain static and dynamic content control tag names.

    C#
    private static List<string> staticContentControls = new List<string>() { "cc1", "cc2" };
    private static List<string> dynamicContentControls = new List<string>() { "cc3", "cc4",
                                                                              "cc5" };
  4. In the main method,
  5. C#
    static void Main(string[] args)
    {
       // convert template to document
       TemplateToDocument("Doc1.dotx", "Doc1.docx");
       File.Copy("Doc1.docx", "Doc2.docx");
       using (WordprocessingDocument wordDoc = WordprocessingDocument.Open("Doc2.docx", true))
       {
             // add content to static content controls
             AddContent(wordDoc);
             // create new content controls
             CreateNewContentControls(wordDoc);
             // add content to dynamically created content controls
             AddContent(wordDoc);
             wordDoc.MainDocumentPart.Document.Save();
        }
    }
  6. TemplateToDocument will convert Doc1.dotx to Doc1.docx.

    MemoryStream presentationStream = null;
    using (Stream tplStream = File.Open(templateFile, FileMode.Open, FileAccess.Read))
    {
       presentationStream = new MemoryStream((int)tplStream.Length);
       tplStream.Copy(presentationStream);
       presentationStream.Position = 0L;
    }
    using (WordprocessingDocument wordPackage = 
                  WordprocessingDocument.Open(presentationStream, true))
      {
             wordPackage.ChangeDocumentType(
                    DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
             MainDocumentPart docPart = wordPackage.MainDocumentPart;
             docPart.AddExternalRelationship("http://schemas.openxmlformats.org/" + 
                    "officeDocument/2006/relationships/attachedTemplate",
             new Uri(templateFile, UriKind.RelativeOrAbsolute));
             docPart.Document.Save();
      }
      File.WriteAllBytes(documentFile, presentationStream.ToArray());  

    The AddContent method will add a sample text to the content placeholder (I have chosen the sample text to be the tag name of the placeholder itself).

    C#
    private static void AddContent(WordprocessingDocument wordDoc)
    {
      var sdtBlocks = wordDoc.MainDocumentPart.Document.Body.ChildElements.OfType<SdtBlock>();
      foreach (SdtBlock block in sdtBlocks)
      {
        if (block.SdtProperties != null)
        {
           Tag blockTag = block.SdtProperties.ChildElements.OfType<Tag>().ElementAt(0);
           if (blockTag != null)
             if (staticContentControls.Contains(blockTag.Val.Value) || 
                         dynamicContentControls.Contains(blockTag.Val.Value))
               block.AddContent(blockTag.Val.Value);
        }
      }
    }  
  7. CreateNewControls would loop through the dynamicContentControls list, create new SdtBlock objects and add them to the Body object of the Document.
  8. C#
    dynamicContentControls.ForEach(cc =>
    {
        // creates a new paragraph
        // just to separate the content placeholders
        Paragraph breakParagraph = new Paragraph();
        // create content placeholder
        SdtBlock sdtBlock = new SdtBlock();
        SdtProperties sdtProperties = new SdtProperties();
        Tag tag = new Tag() { Val = cc };
        // other sdtBlock propertoes code
        SdtContentBlock sdtContentBlock = new SdtContentBlock();
        // sdt content block code
        Paragraph paragraph = new Paragraph();
        Run run = new Run()
        {
            RunProperties = new RunProperties()
            {
                RunStyle = new RunStyle()
                {
                    Val = "PlaceholderText"
                }
            }
        };
        Text text = new Text();
        text.Text = "Click here to enter text.";
        run.Append(text);
        paragraph.Append(run);
        sdtContentBlock.Append(paragraph);
        sdtBlock.Append(sdtProperties);
        sdtBlock.Append(sdtContentBlock);
        // adds the newly created content placeholder to the document
        wordDoc.MainDocumentPart.Document.Body.Append(breakParagraph);
        wordDoc.MainDocumentPart.Document.Body.Append(sdtBlock);
    });
  9. Finally, call the Save() of Document Body object to save the changes done to the document.
  10. C#
    wordDoc.MainDocumentPart.Document.Save();

I have attached a sample solution. Please do have a look.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)