Search code examples
c#ms-wordopenxmlopenxml-sdk

OpenXML insert comment reply into word document C#


I am trying to insert a comment as a reply using OpenXml. If it is not possible, I would like to insert a comment right after a selected comment. So far I am able to insert the comment in the place I want but I cannot get the comment to display when I open the document.

Below is the code to insert the comment.

 using (WordprocessingDocument document = WordprocessingDocument.Open(path + fileName + ".docx", true)){

            // Locate the first paragraph in the document.
            //XMLParagraphAlias firstParagraph = document.MainDocumentPart.Document.Descendants<XMLParagraphAlias>().First();

            XMLCommentsAlias comments = document.MainDocumentPart.WordprocessingCommentsPart.Comments;

            string id = comments.Descendants<DocumentFormat.OpenXml.Wordprocessing.Comment>()
                 .Where(i => i.Id.Value == reply.CurrentCommentID.ToString())
                 .Select(e => e.Id.Value)
                 .First();


             // Compose a new Comment and add it to the Comments part.
             XMLParagraphAlias p = new XMLParagraphAlias(new Run(new Text(reply.ReplyText)));

             string newCommentID = comments.Descendants<DocumentFormat.OpenXml.Wordprocessing.Comment>().Select(e => e.Id.Value).Max();

             XMLCommentAlias cmt = new XMLCommentAlias()
                                  {
                                    Id = newCommentID,
                                    Author = reply.CurrentUserName,
                                    Date = DateTime.Now.Date
                                  };

             XMLCommentAlias comment = comments.Elements<XMLCommentAlias>()
                                       .Where(n => n.Id.Value == reply.CurrentCommentID.ToString())
                                       .First();

             XMLParagraphAlias test2 = comment.Descendants<XMLParagraphAlias>().First();

            cmt.AppendChild(p);        
            comments.AppendChild(cmt);
            comments.Save();

            // Specify the text range for the Comment. 
            // Insert the new CommentRangeStart before the first run of paragraph.
            test2.InsertBefore(new CommentRangeStart() { Id = reply.CurrentCommentID.ToString() }, test2.GetFirstChild<Run>());

            // Insert the new CommentRangeEnd after last run of paragraph.
            var cmtEnd = test2.InsertAfter(new CommentRangeEnd() { Id = reply.CurrentCommentID.ToString() }, test2.Elements<Run>().Last());

            // Compose a run with CommentReference and insert it.
            test2.InsertAfter(new Run(new CommentReference() { Id = reply.CurrentCommentID.ToString() }), cmtEnd);
        }

I can see that the comment is put into the document using the debugger in VS, but it is not being displayed when I open the document.

After the save command is executed the comment is added to the document, but it doesn't display.

The overall goal here is to insert the comment after a specific comment in the list of comments that are contained in the document. Can someone help me find a solution to this?


Solution

  • After following Meister's advice I was able to solve my problem. The comments that are marked as replies are located in the commentsExtended.xml file. To create a relationship with the comment you will need to create a CommentEX object and link the comment reply you are inserting to the comment you are replying to. The code to implement the comment reply is located below. The ParaIdParent property is the paraId of the comment you are replying to.

            private void BuildCommentExtendXML(WordprocessingDocument document, string randomHexBinaryValue, HexBinaryValue commentsParagraphDescendantId)
        {
            var commentsEx = document.MainDocumentPart.WordprocessingCommentsExPart.CommentsEx;
    
            CommentEx commentEx = new CommentEx()
            {
                ParaId = randomHexBinaryValue,
                ParaIdParent = commentsParagraphDescendantId,
                Done = new OnOffValue(false)
            };
            commentsEx.Append(commentEx);
        }