What is a document property you may ask? These are the common tags associated to a document like who is the author, last saved time, title, the total number of pages …
Here is a screenshot of the panel you should be familiar now (if not, follow this Howto to know how to display it).

Sure you know *now * what "is" a document properties but what can I do with them? Maybe you can add some hidden information about a generated document. Or you can define some to-replace content placeholders.
Personally when I need to generate some documents from a template, I used them as some "static" placeholders as I know these values will not change at each new document.
To use them, go to Insert, QuickParts then Fields… Click DocProperty on the left menu and select the property of your choice. You will obtain something like this:

Right-click on a field to toggle its value or code:

Add property using Word

To add the field, follow the same steps as for a classic field:

Add property using OpenXml
This is easier to find, they are stored in CustomFilePropertiesPart.
To display the property name and value, use this snippet:
foreach (var p in package.CustomFilePropertiesPart.Properties.Elements<op.Property>())
{
Console.WriteLine("{0}: {1}", p.Name, p.InnerText);
}
So to add a string value, use:
package.CustomFilePropertiesPart.Properties.Append(new op.Property(
new vt.VTLPWSTR("Some Value")
) { FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}", PropertyId = 2, Name = "MyProperty" });
Hu wait a minute?! Why PropertyId=2? The Id is a required field and should be unique. You can assign yourself some hard-coded value but that's absolutely not safe. We will loop through the Property to retrieve the highest Id.
int nextPropertyId = 2; // 2 is the minimum ID set by MS Office. Don't have a clue why they don't start at 0.
foreach (var p in package.CustomFilePropertiesPart.Properties.Elements<op.Property>())
{
if (p.PropertyId.Value > nextPropertyId) nextPropertyId = p.PropertyId;
}
if(nextPropertyId > 2) nextPropertyId++;
Finally, we will update the body part (+ header and footer). But that have already been solved on this forum post.
XmlNamespaceManager nsMgr = new XmlNamespaceManager(new NameTable());
nsMgr.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
nsMgr.AddNamespace("op", "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties");
XmlDocument document = new XmlDocument();
document.Load(mainPart.GetStream(FileMode.Open, FileAccess.ReadWrite));
XmlNodeList nodes = xmlDocument.SelectNodes(
String.Format("//w:fldSimple[@w:instr=' DOCPROPERTY {0} \\* MERGEFORMAT ']", property.Key), nsMgr);
if (nodes.Count > 0)
{
foreach (XmlNode n in nodes)
{
XmlNodeList textNodes = n.SelectNodes("w:r//w:t", nsMgr);
if (textNodes.Count > 0)
{
textNodes[0].InnerText = property.Value;
for (int j = 1; j < textNodes.Count; j++)
textNodes[j].RemoveAll();
}
}
}
The complete source contains more code (ensure OpenXmlPart exists, disposing resource, …) and accepts a collection bag of custom properties:
UpdateDocumentProperties(WordprocessingDocument package, IDictionary<String, String> properties)
Download code at: OpenXml Demo.zip (5.21 kb)