Screen-Cast: Grouping Content Controls to Create Forms

One of the more interesting scenarios with Open XML WordprocessingML is creating a document that contains a form.  You can send this document to others, who fill out the form and return it to you.  You can then retrieve that data directly from the Open XML markup.  There are two approaches to creating a form when using content controls:

The following screen-cast shows the approach of creating content controls and then grouping them.  It presents a bit of Open XML code that programmatically groups the content controls.

Following is the listing of the small program that I develop in the screen-cast:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

namespace GroupContentControls
{
   
class Program
   
{
       
// Creates an SdtBlock instance and adds its children.
       
public static SdtBlock GenerateSdtBlock()
       
{
           
SdtBlock sdtBlock1 = new SdtBlock();

           
SdtProperties sdtProperties1 = new SdtProperties();
           
SdtId sdtId1 = new SdtId() { Val = -1013684659 };
           
Lock lock1 = new Lock() { Val = LockingValues.ContentLocked };

           
SdtPlaceholder sdtPlaceholder1 = new SdtPlaceholder();
           
DocPartReference docPartReference1 = new DocPartReference() { Val = "DefaultPlaceholder_1081868574" };

            sdtPlaceholder1
.Append(docPartReference1);
           
SdtContentGroup sdtContentGroup1 = new SdtContentGroup();

            sdtProperties1
.Append(sdtId1);
            sdtProperties1
.Append(lock1);
            sdtProperties1
.Append(sdtPlaceholder1);
            sdtProperties1
.Append(sdtContentGroup1);
           
SdtContentBlock sdtContentBlock1 = new SdtContentBlock();

            sdtBlock1
.Append(sdtProperties1);
            sdtBlock1
.Append(sdtContentBlock1);
           
return sdtBlock1;
       
}

       
static void Main(string[] args)
       
{
           
FileInfo f = new FileInfo("../../../EricWhiteForm.docx");
           
FileInfo f2 = new FileInfo("../../../EricWhiteForm - ProgrammaticallyGrouped.docx");
           
if (f2.Exists)
                f2
.Delete();
           
File.Copy(f.FullName, f2.FullName);
           
using (WordprocessingDocument wDoc = WordprocessingDocument.Open(f2.FullName, true))
           
{
               
var sdtBlock = GenerateSdtBlock();
               
var sdtContent = sdtBlock.SdtContentBlock;
               
var body = wDoc.MainDocumentPart.Document.Body;
               
foreach (var child in body.ChildElements)
               
{
                   
if (child is SectionProperties)
                   
{
                       
continue;
                   
}
                    sdtContent
.Append((OpenXmlElement)child.Clone());
               
}
               
var newBody = new Body();
                newBody
.AppendChild(sdtBlock);
                wDoc
.MainDocumentPart.Document.ReplaceChild(newBody, body);
           
}
       
}
   
}
}