wpf-401249-controls-and-libraries-rich-text-editor-track-changes.md
The RichEditControl allows you to track changes in a document. You can view, accept or reject revisions made to a document.
The RichEditControl supports Track Changes in the following formats:
Use the following API to enable Track Changes and specify the revision options:
| API | Description |
|---|---|
| Document.TrackChanges | Provides access to the document’s tracking options (DocumentTrackChangesOptions). |
| DocumentTrackChangesOptions.Enabled | Enables tracking in the document. When tracking is enabled, new document modifications are added as revisions. |
| DocumentTrackChangesOptions.TrackFormatting | |
| DocumentTrackChangesOptions.TrackMoves | Specify whether to track formatting changes (character or paragraph properties’ changes) or content movements. |
The code sample below shows how to enable Track Changes and change formatting options for the specified range. As a result, a new revision is added to the collection:
View Example: How to Manage Tracked Changes in DXRichEdit
DocumentTrackChangesOptions documentTrackChangesOptions = documentProcessor.Document.TrackChanges;
documentTrackChangesOptions.Enabled = true;
documentTrackChangesOptions.TrackFormatting = true;
documentTrackChangesOptions.TrackMoves = true;
//Format the specific phrase in the document:
//This modification is added an a new revision:
DocumentRange[] targetPhrases = documentProcessor.Document.FindAll("We measured hard disk space as a function of USB key space on an IBM PC Junior.", SearchOptions.None);
CharacterProperties characterProperties = documentProcessor.Document.BeginUpdateCharacters(targetPhrases[0]);
characterProperties.FontName = "Arial";
characterProperties.Italic = true;
documentProcessor.Document.EndUpdateCharacters(characterProperties);
Dim documentTrackChangesOptions As DocumentTrackChangesOptions = documentProcessor.Document.TrackChanges
documentTrackChangesOptions.Enabled = True
documentTrackChangesOptions.TrackFormatting = True
documentTrackChangesOptions.TrackMoves = True
'Format the specific phrase in the document:
'This modification is added an a new revision:
Dim targetPhrases() As DocumentRange = documentProcessor.Document.FindAll("We measured hard disk space as a function of USB key space on an IBM PC Junior.", SearchOptions.None)
Dim characterProperties As CharacterProperties = documentProcessor.Document.BeginUpdateCharacters(targetPhrases(0))
characterProperties.FontName = "Arial"
characterProperties.Italic = True
documentProcessor.Document.EndUpdateCharacters(characterProperties)
The Review ribbon tab allows users to keep track of changes made in the current document.
The Track Changes drop-down menu allows you to enable track changes and provide a password to prevent users from disabling Track Changes.
The DXRichEditAnnotationOptions class properties allow you to specify the current author and authors whose revisions should be displayed.
richEditControl1.AnnotationOptions.Author = "Anne Dodsworth";
//Disable showing revisions from all authors
richEditControl1.AnnotationOptions.ShowAllAuthors = false;
//Remove authors whose revisions should not be displayed:
richEditControl1.AnnotationOptions.VisibleAuthors.Remove("Ryan Anita W");
richEditControl1.AnnotationOptions.VisibleAuthors.Remove("Michael Suyama");
richEditControl1.AnnotationOptions.Author = "Anne Dodsworth"
'Disable showing revisions from all authors
richEditControl1.AnnotationOptions.ShowAllAuthors = False
'Remove authors whose revisions should not be displayed:
richEditControl1.AnnotationOptions.VisibleAuthors.Remove("Ryan Anita W")
richEditControl1.AnnotationOptions.VisibleAuthors.Remove("Michael Suyama")
Use the Show Markup drop-down menu to select reviewers whose revisions should be displayed.
The DXRichEditTrackChangesOptions class properties allows you to specify revision display options for the RichEditControl. You can specify a color and format for each revision type and change the review mode.
The TrackChangesOptions options are applied when the document is displayed in the RichEditControl, printed or exported to PDF. These options have no effect when the document is opened in other word processing applications.
Tip
Set the TrackChangesOptions.DisplayForReviewMode property to DisplayForReviewMode.NoMarkup to hide changes when the document is printed or exported to PDF.
<dxre:RichEditControl x:Name="richEditControl1" CommandBarStyle="Ribbon">
<dxre:RichEditControl.AnnotationOptions>
<dxre:DXRichEditAnnotationOptions ShowAllAuthors="True">
<dxre:DXRichEditAnnotationOptions.TrackChangesOptions>
<dxre:DXRichEditTrackChangesOptions DeletedCellColor="Gray"
InsertionColor="Red"
DisplayForReviewMode="SimpleMarkup"
DisplayInsertionStyle="Bold"
DisplayDeletionStyle="DoubleStrikethrough"/>
</dxre:DXRichEditAnnotationOptions.TrackChangesOptions>
</dxre:DXRichEditAnnotationOptions>
</dxre:RichEditControl.AnnotationOptions>
</dxre:RichEditControl>
Use the Display for Review drop-down list to specify how to display changes in the document.
The RichEditControl provides the following modes:
All Markup - displays revisions in details.
Simple Markup - displays revisions indicated by a red line in the margin.
No Markup - displays the document without any visible revisions (as if all revisions are accepted).
The Document.Revisions property provides access to the read-only collection of document revisions.
Call the RevisionCollection.Get method to retrieve revisions related to a document part (main body, header, footer, and text box). Pass the target SubDocument instance as the method’s parameter. The following properties allow you to access a specific document part’s SubDocument :
| Document Part | Property |
|---|---|
| Main Body | RichEditControl.Document |
| Header or Footer | Section.BeginUpdateHeader |
| Section.BeginUpdateFooter | |
| Text Box | TextBox.Document |
The RevisionCollection.Get(DocumentRange) method overload allows you to retrieve changes made to a document range.
The code sample below shows how to retrieve revisions made in the first section’s header and in the first paragraph:
foreach (Shape shape in documentProcessor.Document.Shapes)
//Get revisions from the header:
SubDocument header = richEditControl.Document.Sections[0].BeginUpdateHeader(HeaderFooterType.First);
var sectionRevisions = richEditControl.Document.Revisions.Get(header);
richEditControl.Document.Sections[0].EndUpdateHeader(header);
//Get revisions from the first paragraph:
Paragraph firstParagraph = richEditControl.Document.Paragraphs[0];
var paragraphRevisions = richEditControl.Document.Revisions.Get(firstParagraph.Range);
'Get revisions from the header:
Dim header As SubDocument = richEditControl.Document.Sections(0).BeginUpdateHeader(HeaderFooterType.First)
Dim sectionRevisions = richEditControl.Document.Revisions.Get(header)
richEditControl.Document.Sections(0).EndUpdateHeader(header)
'Get revisions from the first paragraph:
Dim firstParagraph As Paragraph = richEditControl.Document.Paragraphs(0)
Dim paragraphRevisions = richEditControl.Document.Revisions.Get(firstParagraph.Range)
Use the Revision object’s properties to obtain the revision’s date, author, and type. The Revision.Range property provides access to the document range to which the revision is applied. This property retrieves the range after the revision.
Call the Revision.Accept orRevision.Reject method to accept or reject a specific revision.
Use the RevisionCollection.AcceptAll or RevisionCollection.RejectAll method to manage all revisions in the document or in the specific document part.
The code sample below shows how to reject all revisions on the first page’s header:
SubDocument header = documentProcessor.Document.Sections[0].BeginUpdateHeader(HeaderFooterType.First);
documentRevisions.RejectAll(header);
richEditControl.Document.Sections[0].EndUpdateHeader(header);
Dim header As SubDocument = documentProcessor.Document.Sections(0).BeginUpdateHeader(HeaderFooterType.First)
documentRevisions.RejectAll(header)
richEditControl.Document.Sections(0).EndUpdateHeader(header)
Pass the Predicate<T> delegate as one of the method’s parameter to accept or reject all revisions that meet the criteria.
The code sample below rejects all revisions in the first section from the specific author:
//Reject all revisions in the first section from the specific author:
var sectionRevisions = documentRevisions.Get(documentProcessor.Document.Sections[0].Range).Where(x => x.Author == "Janet Leverling");
foreach (Revision revision in sectionRevisions)
revision.Reject();
'Reject all revisions in the first section from the specific author:'
Dim sectionRevisions = documentRevisions.[Get](documentProcessor.Document.Sections(0).Range).Where(Function(x) x.Author = "Janet Leverling")
For Each revision As Revision In sectionRevisions
revision.Reject()
Next
You can use the buttons on the Changes ribbon group or context menu items to move between revisions, accept or reject changes.
When you move text, change it, and then reject this move, a conflict occurs that fires Document.TrackedMovesConflict and RichEditControl.TrackedMovesConflict events. Handle one of the events to specify the version of the text you want to keep (the TrackedMovesConflictEventArgs.ResolveMode property).
Use the TrackedMovesConflictEventArgs.OriginalLocationRange and TrackedMovesConflictEventArgs.NewLocationRange properties to obtain the original and new location range, and the xref:Revision property to retrieve the revision that fired this event.
The code sample below shows how to handle the TrackedMovesConflict event:
private void WordProcessor_TrackedMovesConflict(object sender, TrackedMovesConflictEventArgs e)
{
//Compare the length of the original and new location ranges
//Keep text from the location whose range is the smallest
e.ResolveMode = (e.OriginalLocationRange.Length <= e.NewLocationRange.Length) ? TrackedMovesConflictResolveMode.KeepOriginalLocationText : TrackedMovesConflictResolveMode.KeepNewLocationText;
}
Private Sub WordProcessor_TrackedMovesConflict(ByVal sender As Object, ByVal e As TrackedMovesConflictEventArgs)
'Compare the length of the original and new location ranges
'Keep text from the location whose range is the smallest
e.ResolveMode = If((e.OriginalLocationRange.Length <= e.NewLocationRange.Length), TrackedMovesConflictResolveMode.KeepOriginalLocationText, TrackedMovesConflictResolveMode.KeepNewLocationText)
End Sub
Track Changes has the following limitations: