Insert comment by coordinate

Hello team,

Trying to insert a comment into a Word document using coordinates, however looks like Aspose doesn’t support such scenario.

I have a use case in which I know the (X,Y) position on where a comment should be inserted and the (X,Y) position on where the comment ends, as well as the text that should be surrounded/highlighted by the comment. Positions are against the top-left corner of the page.

Looks like Aspose works with nodes (which looks to be the nature of Word documents). So, if I want to insert the comment, the option that I’m using now is to search for the node that contains the text to highlight/surround with the comment and insert the comment there. The problem with this approach is that the text can appear in multiple places and the comment can be inserted in the wrong position.

I’m wondering if there is way to insert the comment using directly coordinates or if there is a way to know the position of the found node. So I can verify its coordinates intersect with the (X,Y) coordinates of the place I desire to insert.

Providing some code:

public class PatternMatcher : Aspose.Words.Replacing.IReplacingCallback
{
        public ReplacingArgs replaceArgs { get; private set; }

        public ReplaceAction Replacing(ReplacingArgs e)
        {
          // PROBLEM!!! Insert in the first place the text has been found
         // How can we know the coordinates of the found node or how can we insert comment by (X,Y) position.
           replaceArgs = e;
           return ReplaceAction.Stop;
        }
}
// Create comment
var commentParagraph = new Paragraph(document);
commentParagraph.AppendChild(new Run(document, "commentText"));
            
var comment = new Comment(document);
comment.Author = "commentAuthor";
comment.AppendChild(commentParagraph);
            
var start = new CommentRangeStart(document, comment.Id);
var end = new CommentRangeEnd(document, comment.Id);

// Look for text to enclose in comment
PatternMatcher matcher = new PatternMatcher();
document.Range.Replace("textToEncloseInComment", matcher, true);

// Add comment
Run run = (Run)matcher.replaceArgs.MatchNode;
run.ParentNode.InsertBefore(start, run);
run.ParentNode.InsertBefore(comment, run);
run.ParentNode.InsertAfter(end, run);

@Jhovanyamz As you may know MS Word documents are flow documents, there is no “page” concept and nodes doe not have absolute coordinates. So there is no way to add nodes by coordinates.
Consumer applications reflows the document content into pages on the fly. Aspose.Words has it’s own layout engine. You can use LayoutCollector and LayoutEnumerator classes to calculate coordinates of nodes. For example you can use the following code to get start and end coordinates of the Run:

Document doc = new Document(@"C:\Temp\in.docx");
// Get the Run.
Run r = (Run)doc.GetChild(NodeType.Run, 0, true);
// Wrap the run into the bookmark to make it possible to calculate it's coordinates.
BookmarkStart tmpBkStart = new BookmarkStart(doc, "tmp");
BookmarkEnd tmpBkEnd = new BookmarkEnd(doc, tmpBkStart.Name);
r.ParentNode.InsertBefore(tmpBkStart, r);
r.ParentNode.InsertAfter(tmpBkEnd, r);
// create layout collector and enumerator.
LayoutCollector collector = new LayoutCollector(doc);
LayoutEnumerator enumerator = new LayoutEnumerator(doc);
// Calculate coordinates of run start and end.
enumerator.Current = collector.GetEntity(tmpBkStart);
Console.WriteLine("Run start: " + enumerator.Rectangle);
enumerator.Current = collector.GetEntity(tmpBkEnd);
Console.WriteLine("Run end: " + enumerator.Rectangle);

Thanks for the info. This confirms our suspicions on insert comment by coordinates.

I have a follow up question though. We are using PatternMatcher along with document.Range.Replace to search for the node that contains the text we want to enclose in comments.

Looks like that implementation of Replace is marked as deprecated, so probably that is not the best way to search for nodes now. What would be the best way to identify the nodes/run that are associated to a text? (Even if the text is formed by multiple words or even multiple lines?)

@Jhovanyamz You are right the Range.Replace method overload that accepts iReplacingCallback as a parameter is deprecated. You should use another overload that accepts FindReplaceOptions instead. Please see code examples in our documentation:
https://reference.aspose.com/words/net/aspose.words.replacing/ireplacingcallback/

Thanks. Will explore the using new version of method.

Another question, regarding the usage of LayoutCollector and LayoutEnumerator. Looks like LayoutCollector doesn’t work for Runs: LayoutCollector.GetEntity | Aspose.Words for .NET

In my use case, I’m using an implementation of IReplacingCallback to identify the places in the document that contains a given text. The Replacing method will return a Run, I need to check if the found Run intersects with the given coordinates. Since LayoutCollector doesn’t work with Runs, is there a way to parse the Runs to actual nodes? or is there a way to know the position of that run?

@Jhovanyamz Yes, you are right, LayoutCollector and LayoutEnumerator do not work with Run nodes, since Run node can be represented by several spans upon building document layout. That is why in the above provided example to calculate Run node start and end coordinates the run was wrapped into bookmark and BookmakrStart/BookmarkEnd nodes are used as markers for calculation.