How to add comments to bookmark range

i have an existing word document with bookmarks. I need to associate a set of comments to each bookmark.

Bookmark bookmark = document.Range.Bookmarks[bookmarkName];
if (bookmark != null)
{
    Comment comment = new Comment(document, "author", "Author", DateTime.Now); 
    comment.SetText("text");
    bookmark.BookmarkStart.ParentNode.InsertAfter(comment, bookmark.BookmarkStart);
}

using the above code snippet i can insert a comment, but the comment is not covering the whole bookmark range. it is adding at the end or at the start.

How do i add a comment that covers the complete bookmark range

@bala7

To add comments that cover the entire range of a bookmark in a Word document using Aspose.Words, you need to ensure that the comment is inserted in a way that it encompasses the bookmark’s start and end points. The code snippet you provided inserts the comment at the start or end of the bookmark, which is why it appears to cover only part of the bookmark range.

Here’s how you can modify your approach to ensure the comment covers the complete bookmark range:

  1. Create the Comment: Initialize the comment as you have done.
  2. Insert the Comment: Instead of inserting the comment at the start or end of the bookmark, you can insert it at the start of the bookmark and then add the text to the comment.

Here’s an example of how you can achieve this:

// Assuming 'document' is your Document object and 'bookmarkName' is the name of your bookmark
Bookmark bookmark = document.Range.Bookmarks[bookmarkName];
if (bookmark != null)
{
    // Create a new comment
    Comment comment = new Comment(document, "author", "Author", DateTime.Now);
    comment.SetText("This is a comment covering the bookmark range.");

    // Insert the comment at the start of the bookmark
    bookmark.BookmarkStart.ParentNode.InsertAfter(comment, bookmark.BookmarkStart);

    // Now, to ensure the comment covers the entire bookmark range, we need to add the comment's text
    // to the paragraph that contains the bookmark's end
    Node currentNode = bookmark.BookmarkEnd.ParentNode;
    while (currentNode != null && currentNode != bookmark.BookmarkStart.ParentNode)
    {
        // Move to the next node
        currentNode = currentNode.NextSibling;
    }

    // If we reached the end of the bookmark, we can add the comment's text
    if (currentNode != null)
    {
        comment.GetParagraphs().Add(new Paragraph(document));
        comment.GetFirstParagraph().AppendChild(new Run(document, "Comment text covering the bookmark range."));
    }
}

In this code:

  • The comment is created and inserted at the start of the bookmark.
  • The text for the comment is added to ensure it covers the entire range of the bookmark.

This way, the comment will visually represent the entire bookmark range in the document.

If you have any further questions or need additional assistance, feel free to ask!

comment does not have getparagraphs() method

@bala7 The code generated by AI is incorrect. You simply need to wrap the bookmarks content into comment range. Please try using the following code:

Document doc = new Document(@"C:\Temp\in.docx");

foreach (Bookmark bk in doc.Range.Bookmarks)
{
    // Create comment.
    Comment comment = new Comment(doc);
    comment.SetText($"This is comment of {bk.Name} bookmark.");
    // Create comment range start and end associated with the created comment.
    CommentRangeStart start = new CommentRangeStart(doc, comment.Id);
    CommentRangeEnd end = new CommentRangeEnd(doc, comment.Id);

    // Insert comment and it's range start and end around the bookmark.
    bk.BookmarkStart.ParentNode.InsertBefore(start, bk.BookmarkStart);
    bk.BookmarkEnd.ParentNode.InsertAfter(end, bk.BookmarkEnd);
    end.ParentNode.InsertAfter(comment, end);
}

doc.Save(@"C:\Temp\out.docx");

If the end.ParendNode is Aspose.Words.Paragraph, the comment is inserting properly. If the end.ParentNode is Aspose.Words.Table, it is throwing the exception “Cannot insert a node of this type at this location.” The bookmark is pointing towards the cell inside a table.

How to handle that?
@alexey.noskov

@bala7 CommentRangeStart and CommentRangeEnd nodes can be placed only on inline level, i.e. they must be children of paragraph. So, when bookmark is not on inline level (row or cell level) is is required to place CommentRangeStart and CommentRangeEnd nodes inside the corresponding table cells.

@alexey.noskov Any sample code available, how to do that? Please

@bala7 Could you please attach your input and expected output documents for our reference? We will check your documents and provide you more information.

internal class Program
{
    public static string ConvertGuidStringToBookmarkId(string id)
    {
        string bookmarkId = string.Format("_{0}", id);
        bookmarkId = bookmarkId.Replace("-", "_");
        return bookmarkId;
    }

    class CommentInfo
    {
        public string Author;
        public string Text;
    }

    static void Main(string[] args)
    {
        Document document = new Document("CustomCommentsToNative.docx");
        var groupedComments = new Dictionary<string, IEnumerable<CommentInfo>>();
        groupedComments.Add("9bc1b90f-6c13-477d-8def-425c0c722543", new List<CommentInfo>() { new CommentInfo() { Author = "foo", Text = "first comment" } });
        groupedComments.Add("77554859-ea23-4f4f-98f4-3e21cead5b0a", new List<CommentInfo>() { new CommentInfo() { Author = "foo", Text = "first comment" }, new CommentInfo() { Author = "foo1", Text = "first comment1" } });
        foreach (var comments in groupedComments)
        {
            var bookmarkName = ConvertGuidStringToBookmarkId(comments.Key);
            Bookmark bookmark = document.Range.Bookmarks[bookmarkName];
            if (bookmark != null)
            {
                var commentInfo = comments.Value.First();
                Comment comment = new Comment(document, commentInfo.Author, commentInfo.Author, DateTime.Now);
                comment.SetText(commentInfo.Text);

                CommentRangeStart start = new CommentRangeStart(document, comment.Id);
                CommentRangeEnd end = new CommentRangeEnd(document, comment.Id);

                // Insert comment and it's range start and end around the bookmark.
                bookmark.BookmarkStart.ParentNode.InsertBefore(start, bookmark.BookmarkStart);
                bookmark.BookmarkEnd.ParentNode.InsertAfter(end, bookmark.BookmarkEnd);

                end.ParentNode.InsertAfter(comment, end);
                foreach (var nextComments in comments.Value.Skip(1))
                {
                    comment.AddReply(nextComments.Author, nextComments.Author, DateTime.Now, nextComments.Text);
                }
            }
        }
        document.Save(@"c:\temp\test-aspose.docx", SaveFormat.Docx);
    }
}

please use the above code and below file as input,
CustomCommentsToNative.docx (14.0 KB)
the word document contains two bookmarks first one on the word “document” which is inside a paragraph
and another bookmark on a table 2nd row, 2nd column , when i try to add a comment on the bookmark inside the cell, it is failing

@bala7 You can use the following code to deal with column bookmarks:

Document doc = new Document(@"C:\Temp\in.docx");

foreach (Bookmark bk in doc.Range.Bookmarks)
{
    // Create comment.
    Comment comment = new Comment(doc);
    comment.SetText($"This is comment of {bk.Name} bookmark.");
    // Create comment range start and end associated with the created comment.
    CommentRangeStart start = new CommentRangeStart(doc, comment.Id);
    CommentRangeEnd end = new CommentRangeEnd(doc, comment.Id);

    if (bk.IsColumn)
    {
        Table t = (Table)bk.BookmarkStart.GetAncestor(NodeType.Table);
        if (t != null)
        {
            t.FirstRow.Cells[bk.FirstColumn].FirstParagraph.PrependChild(start);
            t.LastRow.Cells[bk.LastColumn].LastParagraph.AppendChild(end);
            t.LastRow.Cells[bk.LastColumn].LastParagraph.AppendChild(comment);
        }
    }
    else
    {
        // Insert comment and it's range start and end around the bookmark.
        bk.BookmarkStart.ParentNode.InsertBefore(start, bk.BookmarkStart);
        bk.BookmarkEnd.ParentNode.InsertAfter(end, bk.BookmarkEnd);
        end.ParentNode.InsertAfter(comment, end);
    }
}

doc.Save(@"C:\Temp\out.docx");

out.docx (12.9 KB)

@alexey.noskov The above solution worked if the table is not null. If the table is null how to handle that, attached code and the sample input

 internal class Program
 {
     public static string ConvertGuidStringToBookmarkId(string id)
     {
         string bookmarkId = string.Format("_{0}", id);
         bookmarkId = bookmarkId.Replace("-", "_");
         return bookmarkId;
     }
     class CommentInfo
     {
         public string Author;
         public string Text;
     }
     static void Main(string[] args)
     {
         Document document = new Document("aspose-null.docx");
         var groupedComments = new Dictionary<string, IEnumerable<CommentInfo>>();
         groupedComments.Add("58d61a17-4376-4f74-ba32-4570f3ad410d", new List<CommentInfo>() { new CommentInfo() { Author = "foo", Text = "first comment" }, new CommentInfo() { Author = "foo", Text = "second comment" } });
         //groupedComments.Add("77554859-ea23-4f4f-98f4-3e21cead5b0a", new List<CommentInfo>() { new CommentInfo() { Author = "foo", Text = "first comment" }, new CommentInfo() { Author = "foo1", Text = "first comment1" } });
         foreach (var comments in groupedComments)
         {
             var bookmarkName = ConvertGuidStringToBookmarkId(comments.Key);
             Bookmark bookmark = document.Range.Bookmarks[bookmarkName];
             if (bookmark != null)
             {
                 var commentInfo = comments.Value.First();
                 Comment comment = new Comment(document, commentInfo.Author, commentInfo.Author, DateTime.Now);
                 comment.SetText(commentInfo.Text);
                 CommentRangeStart start = new CommentRangeStart(document, comment.Id);
                 CommentRangeEnd end = new CommentRangeEnd(document, comment.Id);
                 if (bookmark.IsColumn)
                 {
                     Table t = (Table)bookmark.BookmarkStart.GetAncestor(NodeType.Table);
                     if (t != null)
                     {
                         t.FirstRow.Cells[bookmark.FirstColumn].FirstParagraph.PrependChild(start);
                         t.LastRow.Cells[bookmark.LastColumn].LastParagraph.AppendChild(end);
                         t.LastRow.Cells[bookmark.LastColumn].LastParagraph.AppendChild(comment);
                     }
                 }
                 else
                 {
                     // Insert comment and it's range start and end around the bookmark.
                     bookmark.BookmarkStart.ParentNode.InsertBefore(start, bookmark.BookmarkStart);
                     bookmark.BookmarkEnd.ParentNode.InsertAfter(end, bookmark.BookmarkEnd);
                     if (end.ParentNode is Table || end.ParentNode is Body)
                     {
                         Table t = (Table)bookmark.BookmarkStart.GetAncestor(NodeType.Table);
                         if (t != null)
                         {
                             t.FirstRow.Cells[bookmark.FirstColumn].FirstParagraph.PrependChild(start);
                             t.LastRow.Cells[bookmark.LastColumn].LastParagraph.AppendChild(end);
                             t.LastRow.Cells[bookmark.LastColumn].LastParagraph.AppendChild(comment);
                         }
                     }
                     else
                     {
                         end.ParentNode.InsertAfter(comment, end);
                     }
                     foreach (var nextComments in comments.Value.Skip(1))
                     {
                         comment.AddReply(nextComments.Author, nextComments.Author, DateTime.Now, nextComments.Text);
                     }
                 }
             }
         }
         document.Save(@"c:\temp\test-aspose.docx", SaveFormat.Docx);
     }
 }

aspose-null.docx (20.6 KB)

@bala7 The problem occurs because the bookmark starts in the paragraph and ends in the table:

Please try using the following code:

Document doc = new Document(@"C:\Temp\in.docx");

foreach (Bookmark bk in doc.Range.Bookmarks)
{
    // Create comment.
    Comment comment = new Comment(doc);
    comment.SetText($"This is comment of {bk.Name} bookmark.");
    // Create comment range start and end associated with the created comment.
    CommentRangeStart start = new CommentRangeStart(doc, comment.Id);
    CommentRangeEnd end = new CommentRangeEnd(doc, comment.Id);

    if (bk.IsColumn)
    {
        Table t = (Table)bk.BookmarkStart.GetAncestor(NodeType.Table);
        if (t != null)
        {
            t.FirstRow.Cells[bk.FirstColumn].FirstParagraph.PrependChild(start);
            t.LastRow.Cells[bk.LastColumn].LastParagraph.AppendChild(end);
            t.LastRow.Cells[bk.LastColumn].LastParagraph.AppendChild(comment);
        }
        else
        {
            Console.WriteLine(bk.Name);
        }
    }
    else
    {
        Console.WriteLine(bk.Name);
        // Insert comment and it's range start and end around the bookmark.
        if (bk.BookmarkStart.ParentNode.NodeType == NodeType.Paragraph)
        {
            bk.BookmarkStart.ParentNode.InsertBefore(start, bk.BookmarkStart);
        }
        else
        {
            Node current = bk.BookmarkStart;
            while (current != null && current.NodeType != NodeType.Paragraph)
                current = current.PreviousPreOrder(current.Document);
            if (current != null)
                ((Paragraph)current).AppendChild(start);
        }

        if (bk.BookmarkEnd.ParentNode.NodeType == NodeType.Paragraph)
        {
            bk.BookmarkEnd.ParentNode.InsertAfter(end, bk.BookmarkEnd);
        }
        else
        {
            Node current = bk.BookmarkEnd;
            while (current != null && current.NodeType != NodeType.Paragraph)
                current = current.NextPreOrder(current.Document);
            if (current != null)
            {
                ((Paragraph)current).PrependChild(end);
                ((Paragraph)current).PrependChild(comment);
            }
        }
    }
}

doc.Save(@"C:\Temp\out.docx");