I have fixed this issue now and I think thats it. I am now happy with the Hyperlink implementation.master
| @@ -16,7 +16,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Examples", "Examples\Exampl | |||
| EndProject | |||
| Global | |||
| GlobalSection(TeamFoundationVersionControl) = preSolution | |||
| SccNumberOfProjects = 4 | |||
| SccNumberOfProjects = 5 | |||
| SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} | |||
| SccTeamFoundationServer = https://tfs.codeplex.com/tfs/tfs08 | |||
| SccLocalPath0 = . | |||
| @@ -29,6 +29,9 @@ Global | |||
| SccProjectUniqueName3 = Examples\\Examples.csproj | |||
| SccProjectName3 = Examples | |||
| SccLocalPath3 = Examples | |||
| SccProjectUniqueName4 = ConsoleApplication4\\ConsoleApplication4.csproj | |||
| SccProjectName4 = ConsoleApplication4 | |||
| SccLocalPath4 = ConsoleApplication4 | |||
| EndGlobalSection | |||
| GlobalSection(TestCaseManagementSettings) = postSolution | |||
| CategoryFile = DocX.vsmdi | |||
| @@ -20,6 +20,7 @@ namespace Novacode | |||
| internal int type; | |||
| internal String id; | |||
| internal XElement instrText; | |||
| internal List<XElement> runs; | |||
| /// <summary> | |||
| /// Remove a Hyperlink from this Paragraph only. | |||
| @@ -116,7 +117,18 @@ namespace Novacode | |||
| else | |||
| { | |||
| Xml.ReplaceWith(newRuns); | |||
| XElement separate = XElement.Parse(@" | |||
| <w:r xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'> | |||
| <w:fldChar w:fldCharType='separate'/> | |||
| </w:r>"); | |||
| XElement end = XElement.Parse(@" | |||
| <w:r xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'> | |||
| <w:fldChar w:fldCharType='end' /> | |||
| </w:r>"); | |||
| runs.Last().AddAfterSelf(separate, newRuns, end); | |||
| runs.ForEach(r => r.Remove()); | |||
| } | |||
| this.text = value; | |||
| @@ -193,10 +205,11 @@ namespace Novacode | |||
| this.text = sb.ToString(); | |||
| } | |||
| internal Hyperlink(DocX document, XElement instrText, XElement r) : base(document, r) | |||
| internal Hyperlink(DocX document, XElement instrText, List<XElement> runs) : base(document, null) | |||
| { | |||
| this.type = 1; | |||
| this.instrText = instrText; | |||
| this.runs = runs; | |||
| try | |||
| { | |||
| @@ -207,7 +220,7 @@ namespace Novacode | |||
| this.uri = new Uri(instrText.Value.Substring(start, end - start), UriKind.Absolute); | |||
| StringBuilder sb = new StringBuilder(); | |||
| HelperFunctions.GetTextRecursive(r, ref sb); | |||
| HelperFunctions.GetTextRecursive(new XElement(XName.Get("temp", DocX.w.NamespaceName), runs), ref sb); | |||
| this.text = sb.ToString(); | |||
| } | |||
| } | |||
| @@ -131,22 +131,29 @@ namespace Novacode | |||
| while (e.Name.LocalName != "r") | |||
| e = e.Parent; | |||
| // Take every element until we reach w:fldCharType="end" | |||
| List<XElement> hyperlink_runs = new List<XElement>(); | |||
| foreach (XElement r in e.ElementsAfterSelf(XName.Get("r", DocX.w.NamespaceName))) | |||
| { | |||
| XElement rStyle = r.Descendants(XName.Get("rStyle", DocX.w.NamespaceName)).SingleOrDefault<XElement>(); | |||
| if (rStyle != null) | |||
| // Add this run to the list. | |||
| hyperlink_runs.Add(r); | |||
| XElement fldChar = r.Descendants(XName.Get("fldChar", DocX.w.NamespaceName)).SingleOrDefault<XElement>(); | |||
| if (fldChar != null) | |||
| { | |||
| XAttribute a = rStyle.Attribute(XName.Get("val", DocX.w.NamespaceName)); | |||
| if (a != null && a.Value.Equals("Hyperlink", StringComparison.CurrentCultureIgnoreCase)) | |||
| XAttribute fldCharType = fldChar.Attribute(XName.Get("fldCharType", DocX.w.NamespaceName)); | |||
| if (fldCharType != null && fldCharType.Value.Equals("end", StringComparison.CurrentCultureIgnoreCase)) | |||
| { | |||
| try | |||
| { | |||
| Hyperlink h = new Hyperlink(Document, he, r); | |||
| Hyperlink h = new Hyperlink(Document, he, hyperlink_runs); | |||
| h.mainPart = mainPart; | |||
| hyperlinks.Add(h); | |||
| } | |||
| catch(Exception){} | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| @@ -2992,6 +2999,47 @@ namespace Novacode | |||
| return this; | |||
| } | |||
| /// <summary> | |||
| /// Append a field of type document property, this field will display the custom property cp, at the end of this paragraph. | |||
| /// </summary> | |||
| /// <param name="cp">The custom property to display.</param> | |||
| /// <param name="f">The formatting to use for this text.</param> | |||
| /// <example> | |||
| /// Create, add and display a custom property in a document. | |||
| /// <code> | |||
| ///// Load a document. | |||
| ///using (DocX document = DocX.Create("CustomProperty_Add.docx")) | |||
| ///{ | |||
| /// // Add a few Custom Properties to this document. | |||
| /// document.AddCustomProperty(new CustomProperty("fname", "cathal")); | |||
| /// document.AddCustomProperty(new CustomProperty("age", 24)); | |||
| /// document.AddCustomProperty(new CustomProperty("male", true)); | |||
| /// document.AddCustomProperty(new CustomProperty("newyear2012", new DateTime(2012, 1, 1))); | |||
| /// document.AddCustomProperty(new CustomProperty("fav_num", 3.141592)); | |||
| /// | |||
| /// // Insert a new Paragraph and append a load of DocProperties. | |||
| /// Paragraph p = document.InsertParagraph("fname: ") | |||
| /// .AppendDocProperty(document.CustomProperties["fname"]) | |||
| /// .Append(", age: ") | |||
| /// .AppendDocProperty(document.CustomProperties["age"]) | |||
| /// .Append(", male: ") | |||
| /// .AppendDocProperty(document.CustomProperties["male"]) | |||
| /// .Append(", newyear2012: ") | |||
| /// .AppendDocProperty(document.CustomProperties["newyear2012"]) | |||
| /// .Append(", fav_num: ") | |||
| /// .AppendDocProperty(document.CustomProperties["fav_num"]); | |||
| /// | |||
| /// // Save the changes to the document. | |||
| /// document.Save(); | |||
| ///} | |||
| /// </code> | |||
| /// </example> | |||
| public Paragraph AppendDocProperty(CustomProperty cp, bool trackChanges = false, Formatting f = null) | |||
| { | |||
| this.InsertDocProperty(cp, trackChanges, f); | |||
| return this; | |||
| } | |||
| /// <summary> | |||
| /// Insert a field of type document property, this field will display the custom property cp, at the end of this paragraph. | |||
| /// </summary> | |||
| @@ -3028,12 +3076,16 @@ namespace Novacode | |||
| /// </example> | |||
| public DocProperty InsertDocProperty(CustomProperty cp, bool trackChanges = false, Formatting f = null) | |||
| { | |||
| XElement f_xml = null; | |||
| if (f != null) | |||
| f_xml = f.Xml; | |||
| XElement e = new XElement | |||
| ( | |||
| XName.Get("fldSimple", DocX.w.NamespaceName), | |||
| new XAttribute(XName.Get("instr", DocX.w.NamespaceName), string.Format(@"DOCPROPERTY {0} \* MERGEFORMAT", cp.Name)), | |||
| new XElement(XName.Get("r", DocX.w.NamespaceName), | |||
| new XElement(XName.Get("t", DocX.w.NamespaceName), f.Xml, cp.Value)) | |||
| new XElement(XName.Get("t", DocX.w.NamespaceName), f_xml, cp.Value)) | |||
| ); | |||
| XElement xml = e; | |||
| @@ -85,6 +85,46 @@ namespace UnitTests | |||
| } | |||
| [TestMethod] | |||
| public void Test_CustomProperty_Add() | |||
| { | |||
| // Load a document. | |||
| using (DocX document = DocX.Create("CustomProperty_Add.docx")) | |||
| { | |||
| Assert.IsTrue(document.CustomProperties.Count == 0); | |||
| document.AddCustomProperty(new CustomProperty("fname", "cathal")); | |||
| Assert.IsTrue(document.CustomProperties.Count == 1); | |||
| Assert.IsTrue(document.CustomProperties.ContainsKey("fname")); | |||
| Assert.IsTrue((String)document.CustomProperties["fname"].Value == "cathal"); | |||
| document.AddCustomProperty(new CustomProperty("age", 24)); | |||
| Assert.IsTrue(document.CustomProperties.Count == 2); | |||
| Assert.IsTrue(document.CustomProperties.ContainsKey("age")); | |||
| Assert.IsTrue((int)document.CustomProperties["age"].Value == 24); | |||
| document.AddCustomProperty(new CustomProperty("male", true)); | |||
| Assert.IsTrue(document.CustomProperties.Count == 3); | |||
| Assert.IsTrue(document.CustomProperties.ContainsKey("male")); | |||
| Assert.IsTrue((bool)document.CustomProperties["male"].Value == true); | |||
| document.AddCustomProperty(new CustomProperty("newyear2012", new DateTime(2012, 1, 1))); | |||
| Assert.IsTrue(document.CustomProperties.Count == 4); | |||
| Assert.IsTrue(document.CustomProperties.ContainsKey("newyear2012")); | |||
| Assert.IsTrue((DateTime)document.CustomProperties["newyear2012"].Value == new DateTime(2012, 1, 1)); | |||
| document.AddCustomProperty(new CustomProperty("fav_num", 3.141592)); | |||
| Assert.IsTrue(document.CustomProperties.Count == 5); | |||
| Assert.IsTrue(document.CustomProperties.ContainsKey("fav_num")); | |||
| Assert.IsTrue((double)document.CustomProperties["fav_num"].Value == 3.141592); | |||
| } | |||
| } | |||
| [TestMethod] | |||
| public void Test_EverybodyHasAHome_Loaded() | |||
| { | |||