//
// This code is part of Document Solutions for Word demos.
// Copyright (c) MESCIUS inc. All rights reserved.
//
using System;
using System.IO;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using GrapeCity.Documents.Word;
namespace DsWordWeb.Demos
{
// This example demonstrates how to create a document with multiple ContentControls,
// whose values are mapped to user-created CustomXmlPart file, standard XML file
// which defines various elements and attributes.
// This document also contain a header and a footer with elements that are also mapped to
// proper xml elements.
public class CustomXmlParts
{
public GcWordDocument CreateDocx()
{
var doc = new GcWordDocument();
// Create custom xml part and keep it in the document:
CreateOrderCustomXmlFromString(doc);
// Set custom xml document element value:
SetDeliveryOption(doc, true);
// Compose document with Case properties bound to proper CustomControls:
// Create and map To text field:
CreateOficialBody(doc);
// Create and map Appeal checkbox and AppealDeadline Text control:
CreateDeliveryCheckbox(doc);
// Create Header and map Department xml element:
CreateHeaderWithMappedDepartment(doc);
// Create Header and map document built-in Author xml element:
CreateFooterWithMappedAuthor(doc);
// Done:
return doc;
}
// Retrieve a CustomXmlPart from a document by name:
private static CustomXmlPart GetCustomXmlPartByName(GcWordDocument doc, string name)
{
foreach (var xmlPart in doc.CustomXmlParts)
{
if (string.Compare(xmlPart.XmlDocument.DocumentElement.Name, name, true) == 0)
return xmlPart;
}
throw new ArgumentException(string.Format("Could not find custom xml part {0}", name));
}
// Find 'Order' CustomXmlPart and set its DeliveryAppeal xml element to value provided by method parameter:
private static void SetDeliveryOption(GcWordDocument doc, bool deliveryRequired)
{
var xmlPart = GetCustomXmlPartByName(doc, "Order");
var node = xmlPart.XmlDocument.SelectSingleNode(@"//*[local-name()='Delivery']");
node.InnerText = deliveryRequired ? "true" : "false";
}
// Compose half of document body, map "To" text custom control to proper CustomXml field:
private static void CreateOficialBody(GcWordDocument doc)
{
var p = doc.Body.Paragraphs.Add("Dear ");
var to = p.GetRange().ContentControls.Add(ContentControlType.Text, false);
to.XmlMapping.SetMapping(@"//mescius:To", @"xmlns:mescius='http://developer.mescius.com'");
p.GetRange().Runs.First.Font.Size = 10;
to.Font.Size = 10;
p.GetRange().Runs.Add(",");
doc.Body.Paragraphs.Add();
p = doc.Body.Paragraphs.Add(
"The first shipment of equipment from AMA Ltd has arrived. " +
"We are delighted with every piece. Therefore, we decided to make " +
"our initial purchase larger than anticipated. I am attaching our " +
"purchase order No. 8393 for additional goods. Since you already have " +
"a copy of our Procurement Guidelines, I shall not attach them to " +
"this order. Current Shipping date is ");
// Add shipping Date control, bound to proper section of Order CustomXmlPart:
var dateControl = p.GetRange().ContentControls.Add(ContentControlType.Date, false);
dateControl.DateFormat = "dd.MM.yyyy";
//here we demonstrate how to map CustomControl with namespaces usage, it allows us write
//clean and straight XmlPath. Its the right way of XMlMapping
dateControl.XmlMapping.SetMapping(@"//mescius:Delivery/@DeliveryDate",
@"xmlns:mescius='http://developer.mescius.com'");
p.GetRange().Paragraphs.Add(
"If you want to change it, select checkbox below and change Date, " +
"then send this letter back to me");
dateControl.Font.Italic = true;
p.GetRange().Runs.First.Font.Size = 12;
p.GetRange().Runs.First.Font.Italic = true;
}
// Create footer and map Author built-in property to Text content control:
private static void CreateFooterWithMappedAuthor(GcWordDocument doc)
{
var footer = doc.Body.Sections.First.Footers[HeaderFooterType.Primary];
var p = footer.Body.Paragraphs.Add("Sincerely yours, ");
if (p.Document.Settings.BuiltinProperties.Author == null)
p.Document.Settings.BuiltinProperties.Author = "Nancy Davolio";
// Create Text ContentControl and bind its value to builtin Author property:
var authorTextControl = p.GetRange().ContentControls.Add(ContentControlType.Text, false);
// Use specialized SetMapping overload for document BuiltInProperties.
// here we bind (map) ContentControl to builtin Author property:
authorTextControl.XmlMapping.SetMapping(() => p.Document.Settings.BuiltinProperties.Author);
}
// Create header with Text ContentControl mapped to 'Department' node of 'Order' CustomXml:
private static void CreateHeaderWithMappedDepartment(GcWordDocument doc)
{
// Create Header and fill it with data:
var header = doc.Body.Sections.First.Headers[HeaderFooterType.Primary];
var p = header.Body.Paragraphs.Add();
var departmentTextControl = p.GetRange().ContentControls.Add(ContentControlType.Text, false);
// Get our Case CustomXmlPart:
var xmlPart = GetCustomXmlPartByName(doc, "Order");
var departmentNode = xmlPart.XmlDocument.SelectSingleNode(@"//*[local-name()='Department']");
// Mapping directly to XmlNode:
departmentTextControl.XmlMapping.SetMapping(departmentNode);
}
// Create Delivery part, Checkbox custom control bound to Delivery node and Date custom control
// bound to details of (possible) Delivery date.:
private static void CreateDeliveryCheckbox(GcWordDocument doc)
{
var p = doc.Body.Paragraphs.Add();
// Create checkbox and map it to Shipping node of 'Case' CustomXmlPart:
var checkBox = p.GetRange().ContentControls.Add(ContentControlType.CheckBox, false);
// Here we demonstrate how to map CustomControl ignoring namespaces used in the xml.
// This way should be avoided as much as possible as pretty inefficient:
checkBox.XmlMapping.SetMapping(@"//*[local-name()='Delivery']");
p.GetRange().Runs.Add("Delivery should be done before ");
// Add shipping Date control, bound to proper section of Order CustomXmlPart:
var dateControl = p.GetRange().ContentControls.Add(ContentControlType.Date, false);
dateControl.DateFormat = "dd.MM.yyyy";
// Here we demonstrate how to map CustomControl with namespaces usage, it allows us write
// clean and straight XmlPath. Its the right way of XMlMapping:
dateControl.XmlMapping.SetMapping(@"//mescius:Delivery/@DeliveryDate",
@"xmlns:mescius='http://developer.mescius.com'");
}
// Create XML from a string (see alternative method below):
private static void CreateOrderCustomXmlFromString(GcWordDocument doc)
{
var sb = new System.Text.StringBuilder(201);
const string ns = "'http://developer.mescius.com'";
sb.AppendLine(@"<Order xmlns=" + ns + ">");
sb.AppendLine(@" <To>Mark Donahue</To>");
sb.AppendLine(@" <Department>Shipping department</Department>");
sb.AppendLine(@" <Delivery DeliveryDate=""12.04.2019"">true</Delivery>");
sb.AppendLine(@"</Order>");
XmlDocument xml = new XmlDocument();
xml.LoadXml(sb.ToString());
CustomXmlPart xmlPart = doc.CustomXmlParts.Add(xml, Guid.NewGuid().ToString(), new string[] { ns }, "application/xml");
}
// Create XML by adding individual nodes one by one
// (this method is not used in this sample, the previous
// alternative is used instead):
private static void CreateOrderCustomXml(GcWordDocument doc)
{
// add a custom xml part with custom settings
const string ns = "http://developer.mescius.com";
XmlDocument xml = new XmlDocument();
xml.AppendChild(xml.CreateXmlDeclaration("1.0", "utf-8", null));
XmlElement root = xml.CreateElement("Order", ns);
xml.AppendChild(root);
var to = root.AppendChild(xml.CreateElement("To", ns));
to.InnerText = "Mark Donahue";
var dep = root.AppendChild(xml.CreateElement("Department", ns));
dep.InnerText = "Shipping department";
XmlElement child = xml.CreateElement("Delivery", ns);
child.InnerText = "true";
child.SetAttribute("DeliveryDate", "12.04.2019");
root.AppendChild(child);
CustomXmlPart xmlPart = doc.CustomXmlParts.Add(xml, Guid.NewGuid().ToString(), new string[] { ns }, "application/xml");
// Sad story: we cannot apply schemas to our custom xml parts.
// Unlike in Office excel (where a schema can be serialized inside a document),
// it seems that Word can work with schema URIs only so we cannot place an xsd inside the document.
// This means that we cannot implement native xml-mapping restrictiong and verifying like
// xmlPart.Schemas.Add(CreateCelebrationScheme());
}
}
}