Comments
A comment attaches a note to a piece of text without changing the text itself, the way reviewers annotate a draft in MS Word. Users of a TextControl add, answer, edit and delete comments with the context menu, the ribbon and a sidebar, and your code does the same with the CommentCollection. Read on for both, and for the events that tell your application when comments come and go.
The code below belongs in Form1.cs of a Windows Forms application whose editor is named textControl1, as in Create Your First Windows Forms Application.
How Comments Work
A comment consists of the commented text and the comment string, together a commented text. The editor highlights commented text in a color that depends on the author; the current user's comments are red. A comment belongs to the current user when it is added, which is the first name of UserNames. With an empty list, the author is unknown.
Comments can have replies. A reply refers to the same text but can come from another user at another time. Removing a comment also removes its replies, and never the commented text.
Comments are saved with the document and loaded again in the TX Text Control format (TX), RTF, DOC and DOCX, so comments made in MS Word show up in the editor and the other way around.
Comment Text as a User
Users select text and add a comment from the context menu or with Add Comment on the Proofing tab of the ribbon. An input box opens beside the text; the comment is added when the user closes it with a mouse click or the Enter key. The context menu of a comment has entries to edit, delete and reply to it.
The Comments sidebar lists all comments with their author and time:

To open it from the Comments button of the tab, connect a sidebar with the CommentsSidebar property of the RibbonProofingTab; Sidebar and Panels shows how. Without a ribbon, the CommentsDialog shows the same list in a modeless dialog box:
private void commentsDialogButton_Click(object sender, EventArgs e)
{
CommentsDialog dialog = new CommentsDialog(textControl1);
dialog.Show();
}
Add Comments in Code
Comments returns the CommentCollection of the text part with the input focus. Its Add method has two overloads: without a parameter, it opens the input box for the selected text, and with a CommentedText, it inserts a prepared comment:
private void addCommentButton_Click(object sender, EventArgs e)
{
// Comment the selected text
CommentCollection.AddResult result =
textControl1.Comments.Add(new CommentedText("Please check this figure."));
if (result == CommentCollection.AddResult.NoSelection)
{
MessageBox.Show("Select the text you want to comment on.");
}
}
private void commentHeadingButton_Click(object sender, EventArgs e)
{
// Comment the first 20 characters; the start is one-based
textControl1.Comments.Add(new CommentedText("Shorten the heading.", 1, 20));
}
The code works as follows:
new CommentedText("...")comments the current selection.Addreturns a value of CommentCollection.AddResult:Successful, or a reason such asNoSelection,PositionInvalidorSelectionTooComplex, when the selection isn't one continuous range of text.new CommentedText(comment, start, length)comments a range without selecting it.startis one-based: 1 is the first character.textControl1.Comments.Add()without a parameter opens the input box for the user, as the ribbon button does.
Read and Answer Comments
The collection enumerates all comments and replies of the text part. GetItem returns the comment at the input position, GetItem(true) the next one and GetItem(false) the previous one, or null if there is none. The following code lists the comments with their replies and answers the comment at the input position:
private void listCommentsButton_Click(object sender, EventArgs e)
{
System.Text.StringBuilder report = new System.Text.StringBuilder();
foreach (CommentedText comment in textControl1.Comments)
{
// Replies are listed below the comment they answer
if (comment.RepliedComment != null)
{
continue;
}
report.AppendLine($"\"{comment.Text}\": {comment.Comment} " +
$"({comment.UserName}, {comment.CreationTime.ToLocalTime()})");
foreach (CommentedText reply in comment.Replies ?? new CommentedText[0])
{
report.AppendLine($" {reply.UserName}: {reply.Comment}");
}
}
MessageBox.Show(report.ToString(), "Comments");
}
private void replyButton_Click(object sender, EventArgs e)
{
CommentedText comment = textControl1.Comments.GetItem();
if (comment != null)
{
textControl1.Comments.Add(new CommentedText("Done.", comment));
}
}
- Text is the commented text and Comment the comment, which can also be set.
- UserName is the author and CreationTime the time in UTC.
- Replies returns the replies, or
nullif there are none, and RepliedComment the comment a reply answers. new CommentedText(comment, repliedComment)creates a reply, whichAddinserts.
Change the Highlighting
CommentHighlightMode of the TextControl decides when commented text is highlighted:
HighlightMode.Activated, the default, highlights a comment while the input position is in it.HighlightMode.Alwayshighlights all comments.HighlightMode.Neverhighlights none.
A single comment can differ from this setting with its own HighlightMode and HighlightColor. Active set to false deactivates a comment: it is no longer highlighted, and GetItem skips it.
React to Comments
The following events inform your application about comments. Each handler receives CommentEventArgs, whose CommentedText is the comment:
| Event | Occurs when |
|---|---|
| CommentCreated | A piece of text has been commented |
| CommentDeleted | A comment has been removed |
| CommentChanged | The text of a comment has been changed |
| CommentStateChanged | A comment has become active or inactive |
| CommentedTextEntered, CommentedTextLeft | The input position has moved into or out of commented text |
The following handler shows the comment at the input position in the title bar of the form. Connect it on the Events page of the Properties window, or with textControl1.CommentedTextEntered += textControl1_CommentedTextEntered; in the constructor:
private void textControl1_CommentedTextEntered(object sender, CommentEventArgs e)
{
Text = $"{e.CommentedText.UserName}: {e.CommentedText.Comment}";
}
To remove the comments of every text part before a document is sent, see Comments and Tracked Changes. To read the comments of stored documents without the editor, for example to import them into a database, use the Comments collection of a ServerTextControl, as shown in the blog article Extracting Comments from DOCX Files in .NET C#.
Next Steps
- Track Changes: record and review insertions and deletions.
- Document Protection and Editable Regions: the user names that also decide who may edit which region.
- Sidebar and Panels: the Comments panel beside the editor.
- Built-in Dialog Boxes: the other dialog boxes of the editor.