CustomXmlParts.cs
  1. //
  2. // This code is part of Document Solutions for Word demos.
  3. // Copyright (c) MESCIUS inc. All rights reserved.
  4. //
  5. using System;
  6. using System.IO;
  7. using System.Drawing;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Xml;
  11. using GrapeCity.Documents.Word;
  12.  
  13. namespace DsWordWeb.Demos
  14. {
  15. // This example demonstrates how to create a document with multiple ContentControls,
  16. // whose values are mapped to user-created CustomXmlPart file, standard XML file
  17. // which defines various elements and attributes.
  18. // This document also contain a header and a footer with elements that are also mapped to
  19. // proper xml elements.
  20. public class CustomXmlParts
  21. {
  22. public GcWordDocument CreateDocx()
  23. {
  24. var doc = new GcWordDocument();
  25.  
  26. // Create custom xml part and keep it in the document:
  27. CreateOrderCustomXmlFromString(doc);
  28.  
  29. // Set custom xml document element value:
  30. SetDeliveryOption(doc, true);
  31.  
  32. // Compose document with Case properties bound to proper CustomControls:
  33.  
  34. // Create and map To text field:
  35. CreateOficialBody(doc);
  36.  
  37. // Create and map Appeal checkbox and AppealDeadline Text control:
  38. CreateDeliveryCheckbox(doc);
  39.  
  40. // Create Header and map Department xml element:
  41. CreateHeaderWithMappedDepartment(doc);
  42.  
  43. // Create Header and map document built-in Author xml element:
  44. CreateFooterWithMappedAuthor(doc);
  45.  
  46. // Done:
  47. return doc;
  48. }
  49.  
  50. // Retrieve a CustomXmlPart from a document by name:
  51. private static CustomXmlPart GetCustomXmlPartByName(GcWordDocument doc, string name)
  52. {
  53. foreach (var xmlPart in doc.CustomXmlParts)
  54. {
  55. if (string.Compare(xmlPart.XmlDocument.DocumentElement.Name, name, true) == 0)
  56. return xmlPart;
  57. }
  58. throw new ArgumentException(string.Format("Could not find custom xml part {0}", name));
  59. }
  60.  
  61.  
  62. // Find 'Order' CustomXmlPart and set its DeliveryAppeal xml element to value provided by method parameter:
  63. private static void SetDeliveryOption(GcWordDocument doc, bool deliveryRequired)
  64. {
  65. var xmlPart = GetCustomXmlPartByName(doc, "Order");
  66.  
  67. var node = xmlPart.XmlDocument.SelectSingleNode(@"//*[local-name()='Delivery']");
  68. node.InnerText = deliveryRequired ? "true" : "false";
  69. }
  70.  
  71. // Compose half of document body, map "To" text custom control to proper CustomXml field:
  72. private static void CreateOficialBody(GcWordDocument doc)
  73. {
  74. var p = doc.Body.Paragraphs.Add("Dear ");
  75. var to = p.GetRange().ContentControls.Add(ContentControlType.Text, false);
  76. to.XmlMapping.SetMapping(@"//mescius:To", @"xmlns:mescius='http://developer.mescius.com'");
  77.  
  78. p.GetRange().Runs.First.Font.Size = 10;
  79. to.Font.Size = 10;
  80. p.GetRange().Runs.Add(",");
  81. doc.Body.Paragraphs.Add();
  82.  
  83. p = doc.Body.Paragraphs.Add(
  84. "The first shipment of equipment from AMA Ltd has arrived. " +
  85. "We are delighted with every piece. Therefore, we decided to make " +
  86. "our initial purchase larger than anticipated. I am attaching our " +
  87. "purchase order No. 8393 for additional goods. Since you already have " +
  88. "a copy of our Procurement Guidelines, I shall not attach them to " +
  89. "this order. Current Shipping date is ");
  90.  
  91. // Add shipping Date control, bound to proper section of Order CustomXmlPart:
  92. var dateControl = p.GetRange().ContentControls.Add(ContentControlType.Date, false);
  93. dateControl.DateFormat = "dd.MM.yyyy";
  94. //here we demonstrate how to map CustomControl with namespaces usage, it allows us write
  95. //clean and straight XmlPath. Its the right way of XMlMapping
  96. dateControl.XmlMapping.SetMapping(@"//mescius:Delivery/@DeliveryDate",
  97. @"xmlns:mescius='http://developer.mescius.com'");
  98. p.GetRange().Paragraphs.Add(
  99. "If you want to change it, select checkbox below and change Date, " +
  100. "then send this letter back to me");
  101. dateControl.Font.Italic = true;
  102.  
  103. p.GetRange().Runs.First.Font.Size = 12;
  104. p.GetRange().Runs.First.Font.Italic = true;
  105. }
  106.  
  107. // Create footer and map Author built-in property to Text content control:
  108. private static void CreateFooterWithMappedAuthor(GcWordDocument doc)
  109. {
  110. var footer = doc.Body.Sections.First.Footers[HeaderFooterType.Primary];
  111. var p = footer.Body.Paragraphs.Add("Sincerely yours, ");
  112.  
  113. if (p.Document.Settings.BuiltinProperties.Author == null)
  114. p.Document.Settings.BuiltinProperties.Author = "Nancy Davolio";
  115.  
  116. // Create Text ContentControl and bind its value to builtin Author property:
  117. var authorTextControl = p.GetRange().ContentControls.Add(ContentControlType.Text, false);
  118.  
  119. // Use specialized SetMapping overload for document BuiltInProperties.
  120. // here we bind (map) ContentControl to builtin Author property:
  121. authorTextControl.XmlMapping.SetMapping(() => p.Document.Settings.BuiltinProperties.Author);
  122. }
  123.  
  124. // Create header with Text ContentControl mapped to 'Department' node of 'Order' CustomXml:
  125. private static void CreateHeaderWithMappedDepartment(GcWordDocument doc)
  126. {
  127. // Create Header and fill it with data:
  128. var header = doc.Body.Sections.First.Headers[HeaderFooterType.Primary];
  129. var p = header.Body.Paragraphs.Add();
  130. var departmentTextControl = p.GetRange().ContentControls.Add(ContentControlType.Text, false);
  131.  
  132. // Get our Case CustomXmlPart:
  133. var xmlPart = GetCustomXmlPartByName(doc, "Order");
  134.  
  135. var departmentNode = xmlPart.XmlDocument.SelectSingleNode(@"//*[local-name()='Department']");
  136. // Mapping directly to XmlNode:
  137. departmentTextControl.XmlMapping.SetMapping(departmentNode);
  138. }
  139.  
  140. // Create Delivery part, Checkbox custom control bound to Delivery node and Date custom control
  141. // bound to details of (possible) Delivery date.:
  142. private static void CreateDeliveryCheckbox(GcWordDocument doc)
  143. {
  144. var p = doc.Body.Paragraphs.Add();
  145.  
  146. // Create checkbox and map it to Shipping node of 'Case' CustomXmlPart:
  147. var checkBox = p.GetRange().ContentControls.Add(ContentControlType.CheckBox, false);
  148.  
  149. // Here we demonstrate how to map CustomControl ignoring namespaces used in the xml.
  150. // This way should be avoided as much as possible as pretty inefficient:
  151. checkBox.XmlMapping.SetMapping(@"//*[local-name()='Delivery']");
  152.  
  153. p.GetRange().Runs.Add("Delivery should be done before ");
  154.  
  155. // Add shipping Date control, bound to proper section of Order CustomXmlPart:
  156. var dateControl = p.GetRange().ContentControls.Add(ContentControlType.Date, false);
  157. dateControl.DateFormat = "dd.MM.yyyy";
  158. // Here we demonstrate how to map CustomControl with namespaces usage, it allows us write
  159. // clean and straight XmlPath. Its the right way of XMlMapping:
  160. dateControl.XmlMapping.SetMapping(@"//mescius:Delivery/@DeliveryDate",
  161. @"xmlns:mescius='http://developer.mescius.com'");
  162. }
  163.  
  164. // Create XML from a string (see alternative method below):
  165. private static void CreateOrderCustomXmlFromString(GcWordDocument doc)
  166. {
  167. var sb = new System.Text.StringBuilder(201);
  168. const string ns = "'http://developer.mescius.com'";
  169.  
  170. sb.AppendLine(@"<Order xmlns=" + ns + ">");
  171. sb.AppendLine(@" <To>Mark Donahue</To>");
  172. sb.AppendLine(@" <Department>Shipping department</Department>");
  173. sb.AppendLine(@" <Delivery DeliveryDate=""12.04.2019"">true</Delivery>");
  174. sb.AppendLine(@"</Order>");
  175.  
  176. XmlDocument xml = new XmlDocument();
  177. xml.LoadXml(sb.ToString());
  178. CustomXmlPart xmlPart = doc.CustomXmlParts.Add(xml, Guid.NewGuid().ToString(), new string[] { ns }, "application/xml");
  179. }
  180.  
  181. // Create XML by adding individual nodes one by one
  182. // (this method is not used in this sample, the previous
  183. // alternative is used instead):
  184. private static void CreateOrderCustomXml(GcWordDocument doc)
  185. {
  186. // add a custom xml part with custom settings
  187. const string ns = "http://developer.mescius.com";
  188. XmlDocument xml = new XmlDocument();
  189.  
  190. xml.AppendChild(xml.CreateXmlDeclaration("1.0", "utf-8", null));
  191. XmlElement root = xml.CreateElement("Order", ns);
  192. xml.AppendChild(root);
  193.  
  194. var to = root.AppendChild(xml.CreateElement("To", ns));
  195. to.InnerText = "Mark Donahue";
  196.  
  197. var dep = root.AppendChild(xml.CreateElement("Department", ns));
  198. dep.InnerText = "Shipping department";
  199.  
  200. XmlElement child = xml.CreateElement("Delivery", ns);
  201. child.InnerText = "true";
  202. child.SetAttribute("DeliveryDate", "12.04.2019");
  203.  
  204. root.AppendChild(child);
  205.  
  206. CustomXmlPart xmlPart = doc.CustomXmlParts.Add(xml, Guid.NewGuid().ToString(), new string[] { ns }, "application/xml");
  207.  
  208. // Sad story: we cannot apply schemas to our custom xml parts.
  209. // Unlike in Office excel (where a schema can be serialized inside a document),
  210. // it seems that Word can work with schema URIs only so we cannot place an xsd inside the document.
  211. // This means that we cannot implement native xml-mapping restrictiong and verifying like
  212. // xmlPart.Schemas.Add(CreateCelebrationScheme());
  213. }
  214. }
  215. }
  216.