# Track Changes

> Turn on track changes in a WPF TextControl in XAML or code, accept or reject tracked changes, handle CannotTrackChange and connect the Tracked Changes sidebar.

- **Product:** TX Text Control .NET for WPF
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for WPF > Document Editor > Track Changes
- **3855 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/track-changes/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/track-changes/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/track-changes/llms-full.txt

---

When a document passes through several reviewers, each edit should stay visible until someone approves it. The WPF `TextControl` records insertions and deletions as tracked changes, with author and time, and lets the user or your code accept or reject them. Read on to turn tracking on in XAML or code, work through the changes and react to them with event handlers.

The examples assume a window with a `TextControl` named `textControl1` in *MainWindow.xaml*, as built in [Create Your First WPF Application](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/document-editor/first-application/llms-full.txt).

### How Track Changes Works

With tracking turned on, every insertion and deletion becomes a *tracked change* that belongs to the current user. The editor shows inserted text in color and deleted text in color and struck through, with a color per author; the current user's changes are red by default.

Accepting a change keeps it and removes its mark. Rejecting it restores the previous text: inserted text disappears and deleted text returns. Until one of the two happens, the change stays in the document, even after tracking has been turned off, which only ends the recording of new changes.

The TX Text Control format (TX), RTF, DOC and DOCX save tracked changes and load them again, including changes that MS Word recorded in a DOCX file.

A few complex operations, such as deleting a table column or merging table cells, can't be tracked. For those, the editor asks the user in a message box whether to go ahead without tracking; see [Handle Changes That Can't Be Tracked](#handle-changes-that-can-t-be-tracked).

### Review Changes in the Ribbon

The **Proofing** tab, a [RibbonProofingTab](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/ribbonproofingtab/llms-full.txt), contains a **Track Changes** group. The **Track Changes** button turns tracking on and off, further buttons accept or reject changes and move from one change to the next, and the **Tracked Changes** split button opens a sidebar with all changes, their authors and times:

![The TX Text Control Words sample for WPF with a red, underlined insertion in the document and the Tracked Changes sidebar listing the change as Text Inserted by John with date and time.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-wpf/tracked-changes-sidebar.1a722907.webp)

In WPF, the tab refers to the sidebar by its name. Give the sidebar an `x:Name` and set the [TrackedChangesSidebar](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/ribbonproofingtab/trackedchangessidebar-property/llms-full.txt) property of the tab to that name, as a string. The `TextControl` finds the tab the same way, through its [RibbonProofingTab](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/ribbonproofingtab-property/llms-full.txt) property. [Sidebar and Panels](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/ribbon-ui/sidebar/llms-full.txt) and [Connecting Ribbon Tabs in XAML](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/ribbon-ui/ribbon-xaml/llms-full.txt) show the markup.

### Set the Author and Turn On Tracking

New changes belong to the current user, the first name of [UserNames](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/usernames-property/llms-full.txt). With an empty list, the author is unknown. [IsTrackChangesEnabled](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/istrackchangesenabled-property/llms-full.txt) switches the recording on and off.

Connect a handler to the `Loaded` event of the control in *MainWindow.xaml*. The same element also connects the handlers of the sections below:

```xml
<WPF:TextControl x:Name="textControl1"
                Loaded="TextControl1_Loaded"
                CannotTrackChange="TextControl1_CannotTrackChange"
                TrackedChangeCreated="TextControl1_TrackedChangeCreated" />
```

In *MainWindow.xaml.cs*, the `Loaded` handler sets the author and turns tracking on:

```csharp
using System;
using System.Windows;
using TXTextControl;

namespace SampleApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void TextControl1_Loaded(object sender, RoutedEventArgs e)
        {
            // The first name is the author of new changes and comments
            textControl1.UserNames = new string[] { "Tim Typer" };

            // Record all insertions and deletions from now on
            textControl1.IsTrackChangesEnabled = true;
        }
    }
}
```

Use the namespace of your project instead of `SampleApp`. `IsTrackChangesEnabled` can also be set as an attribute in XAML, `IsTrackChangesEnabled="True"`. Take the user name from the sign-in of your application. The same list controls which editable regions of a protected document a user may change; see [Document Protection and Editable Regions](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/protection/llms-full.txt).

### List the Tracked Changes

[TrackedChanges](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/trackedchanges-property/llms-full.txt) returns a [TrackedChangeCollection](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchangecollection/llms-full.txt), which holds the changes of the text part with the input focus: the main text, a header or footer, or a text frame. The collection and the [TrackedChange](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/llms-full.txt) objects in it belong to the `TXTextControl` namespace, not to `TXTextControl.WPF`. The following method shows all changes in a message box:

```csharp
private void ShowTrackedChanges()
{
    System.Text.StringBuilder report = new System.Text.StringBuilder();

    foreach (TrackedChange change in textControl1.TrackedChanges)
    {
        // ChangeTime is UTC; show it in local time
        report.AppendLine($"{change.Number}. {change.ChangeKind} by {change.UserName}, " +
            $"{change.ChangeTime.ToLocalTime()}: {change.Text}");
    }

    MessageBox.Show(report.ToString(), "Tracked Changes");
}
```

The properties of a change:

| Property | Value |
|---|---|
| [ChangeKind](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/changekind-property/llms-full.txt) | `InsertedText` or `DeletedText` |
| [UserName](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/username-property/llms-full.txt) | The author; `null` or an empty string for an unknown user |
| [ChangeTime](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/changetime-property/llms-full.txt) | The date and time of the change in Coordinated Universal Time (UTC) |
| [Text](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/text-property/llms-full.txt) | The inserted or deleted text |
| [Start](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/start-property/llms-full.txt), [Length](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/length-property/llms-full.txt) | The position of the change; `Start` is one-based |
| [Number](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/number-property/llms-full.txt) | The place of the change in the text, starting at 1; the [indexer](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchangecollection/item-property/llms-full.txt) of the collection takes it |

### Accept and Reject Changes

A tracked change leaves the document only through [TrackedChangeCollection.Remove](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchangecollection/remove-method/llms-full.txt). Its second parameter accepts the change with `true` and rejects it with `false`. [GetItem](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchangecollection/getitem-method/llms-full.txt) returns the change at the input position, or `null`:

```csharp
private void AcceptButton_Click(object sender, RoutedEventArgs e)
{
    // The change at the input position, or null
    TrackedChange change = textControl1.TrackedChanges.GetItem();

    if (change != null)
    {
        textControl1.TrackedChanges.Remove(change, true);
    }
}

private void RemoveAllChanges(bool accept)
{
    // Every call removes one change, so always take the first one
    while (textControl1.TrackedChanges.Count > 0)
    {
        if (!textControl1.TrackedChanges.Remove(textControl1.TrackedChanges[1], accept))
        {
            break;
        }
    }
}
```

The code works as follows:

- `AcceptButton_Click` is the `Click` handler of a WPF `Button` and accepts the change that contains the input position.
- `RemoveAllChanges(true)` accepts all changes of the text part and `RemoveAllChanges(false)` rejects them. Because the remaining changes are renumbered after each removal, it always removes change number 1. If `Remove` returns `false`, the change could not be removed and the loop stops.

### Move Through the Changes

`GetItem(true)` returns the next change after the input position and `GetItem(false)` the previous one. [ScrollTo](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/scrollto-method/llms-full.txt) moves the input position to the change and scrolls it into view, and [Select](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/select-method/llms-full.txt) selects its text:

```csharp
private void NextChangeButton_Click(object sender, RoutedEventArgs e)
{
    TrackedChange next = textControl1.TrackedChanges.GetItem(true);

    if (next != null)
    {
        next.ScrollTo();
        next.Select();
    }
}
```

### Handle Changes That Can't Be Tracked

[CannotTrackChange](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/cannottrackchange-event/llms-full.txt) occurs before an operation that can't be tracked. Unless a handler takes over, the editor shows its message box. The handler below, connected in the XAML above, refuses every such operation without asking:

```csharp
private void TextControl1_CannotTrackChange(object sender, CannotTrackChangeEventArgs e)
{
    // Don't change the document, and don't show the message box
    e.Cancel = true;
    e.Handled = true;
}
```

[CannotTrackChangeEventArgs](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/cannottrackchangeeventargs/llms-full.txt) has three properties:

- [Handled](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/cannottrackchangeeventargs/handled-property/llms-full.txt), `false` by default, suppresses the message box when set to `true`.
- [Cancel](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/cannottrackchangeeventargs/cancel-property/llms-full.txt), `true` by default, cancels the operation. With `false`, the document is changed without tracking.
- [DefaultMessage](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/cannottrackchangeeventargs/defaultmessage-property/llms-full.txt) is the text the message box would show, for a dialog window of your own.

### React to Tracked Changes

Four events report tracked changes. Their handlers receive [TrackedChangeEventArgs](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchangeeventargs/llms-full.txt) with the change in its [TrackedChange](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchangeeventargs/trackedchange-property/llms-full.txt) property:

- [TrackedChangeCreated](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/trackedchangecreated-event/llms-full.txt) when a change has been recorded.
- [TrackedChangeDeleted](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/trackedchangedeleted-event/llms-full.txt) when a change has been accepted or rejected.
- [TrackedChangeChanged](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/trackedchangechanged-event/llms-full.txt) when the text of a change has been altered.
- [TrackedChangeStateChanged](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/trackedchangestatechanged-event/llms-full.txt) when a change has become active or inactive.

The following handler writes the latest change into the title of the window:

```csharp
private void TextControl1_TrackedChangeCreated(object sender, TrackedChangeEventArgs e)
{
    Title = $"{e.TrackedChange.ChangeKind} by {e.TrackedChange.UserName}";
}
```

These are ordinary .NET events, which XAML attributes connect as shown above. [Events](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/events/llms-full.txt) explains the event model of the WPF `TextControl`.

### Change How Changes Are Highlighted

A few properties of a `TrackedChange` change its appearance:

- [HighlightColor](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/highlightcolor-property/llms-full.txt) is a `System.Drawing.Color`, not a WPF `System.Windows.Media.Color`. While it is [DefaultHighlightColor](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/defaulthighlightcolor-property/llms-full.txt), changes of other users get a color derived from the user name.
- [HighlightMode](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/highlightmode-property/llms-full.txt) takes `HighlightMode.Always` or `HighlightMode.Never`.
- [Active](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/trackedchange/active-property/llms-full.txt) with `false` deactivates the change: it isn't highlighted, and `GetItem` doesn't return it.

For documents that nobody opens in the editor, a `ServerTextControl` has the same `TrackedChanges` collection; see [Comments and Tracked Changes](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/comments-changes/llms-full.txt). The blog article [Inspect and Process Track Changes in DOCX Documents with TX Text Control with .NET C#](https://www.textcontrol.com/blog/2026/03/10/inspect-and-process-track-changes-in-docx-documents-with-tx-text-control-with-dotnet-csharp/) filters tracked changes by author, kind and date that way.

### Next Steps

- [Comments](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/comments/llms-full.txt): comment on text and answer comments during a review.
- [Document Protection and Editable Regions](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/protection/llms-full.txt): lock a document except for the regions of certain users.
- [Sidebar and Panels](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/ribbon-ui/sidebar/llms-full.txt): add the Tracked Changes and Comments panels to the window.
- [Events](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/events/llms-full.txt): how the events of the WPF `TextControl` are connected.

---

## Nearby

- **Previous:** [Signature Fields](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/signature-fields/llms-full.txt)
- **Next:** [Comments](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/comments/llms-full.txt)
