I have fixed this issue now and I think thats it. I am now happy with the Hyperlink implementation.master
| EndProject | EndProject | ||||
| Global | Global | ||||
| GlobalSection(TeamFoundationVersionControl) = preSolution | GlobalSection(TeamFoundationVersionControl) = preSolution | ||||
| SccNumberOfProjects = 4 | |||||
| SccNumberOfProjects = 5 | |||||
| SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} | SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} | ||||
| SccTeamFoundationServer = https://tfs.codeplex.com/tfs/tfs08 | SccTeamFoundationServer = https://tfs.codeplex.com/tfs/tfs08 | ||||
| SccLocalPath0 = . | SccLocalPath0 = . | ||||
| SccProjectUniqueName3 = Examples\\Examples.csproj | SccProjectUniqueName3 = Examples\\Examples.csproj | ||||
| SccProjectName3 = Examples | SccProjectName3 = Examples | ||||
| SccLocalPath3 = Examples | SccLocalPath3 = Examples | ||||
| SccProjectUniqueName4 = ConsoleApplication4\\ConsoleApplication4.csproj | |||||
| SccProjectName4 = ConsoleApplication4 | |||||
| SccLocalPath4 = ConsoleApplication4 | |||||
| EndGlobalSection | EndGlobalSection | ||||
| GlobalSection(TestCaseManagementSettings) = postSolution | GlobalSection(TestCaseManagementSettings) = postSolution | ||||
| CategoryFile = DocX.vsmdi | CategoryFile = DocX.vsmdi |
| internal int type; | internal int type; | ||||
| internal String id; | internal String id; | ||||
| internal XElement instrText; | internal XElement instrText; | ||||
| internal List<XElement> runs; | |||||
| /// <summary> | /// <summary> | ||||
| /// Remove a Hyperlink from this Paragraph only. | /// Remove a Hyperlink from this Paragraph only. | ||||
| else | 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; | this.text = value; | ||||
| this.text = sb.ToString(); | 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.type = 1; | ||||
| this.instrText = instrText; | this.instrText = instrText; | ||||
| this.runs = runs; | |||||
| try | try | ||||
| { | { | ||||
| this.uri = new Uri(instrText.Value.Substring(start, end - start), UriKind.Absolute); | this.uri = new Uri(instrText.Value.Substring(start, end - start), UriKind.Absolute); | ||||
| StringBuilder sb = new StringBuilder(); | 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(); | this.text = sb.ToString(); | ||||
| } | } | ||||
| } | } |
| while (e.Name.LocalName != "r") | while (e.Name.LocalName != "r") | ||||
| e = e.Parent; | 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))) | 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 | try | ||||
| { | { | ||||
| Hyperlink h = new Hyperlink(Document, he, r); | |||||
| Hyperlink h = new Hyperlink(Document, he, hyperlink_runs); | |||||
| h.mainPart = mainPart; | h.mainPart = mainPart; | ||||
| hyperlinks.Add(h); | hyperlinks.Add(h); | ||||
| } | } | ||||
| catch(Exception){} | catch(Exception){} | ||||
| break; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return this; | 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> | /// <summary> | ||||
| /// Insert a field of type document property, this field will display the custom property cp, at the end of this paragraph. | /// Insert a field of type document property, this field will display the custom property cp, at the end of this paragraph. | ||||
| /// </summary> | /// </summary> | ||||
| /// </example> | /// </example> | ||||
| public DocProperty InsertDocProperty(CustomProperty cp, bool trackChanges = false, Formatting f = null) | 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 | XElement e = new XElement | ||||
| ( | ( | ||||
| XName.Get("fldSimple", DocX.w.NamespaceName), | XName.Get("fldSimple", DocX.w.NamespaceName), | ||||
| new XAttribute(XName.Get("instr", DocX.w.NamespaceName), string.Format(@"DOCPROPERTY {0} \* MERGEFORMAT", cp.Name)), | 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("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; | XElement xml = e; |
| } | } | ||||
| [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] | [TestMethod] | ||||
| public void Test_EverybodyHasAHome_Loaded() | public void Test_EverybodyHasAHome_Loaded() | ||||
| { | { |