# Track Changes

> Record insertions and deletions in a Windows Forms TextControl: set the author with UserNames, list, accept and reject TrackedChange objects and handle events.

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

---

Contracts, reports and other documents that several people revise need a record of who changed what. With track changes turned on, the `TextControl` marks every insertion and deletion with its author and time, and a reviewer later accepts or rejects each change, in the ribbon or in your code. The sections below cover both ways, from turning tracking on to reacting to new changes.

The code goes into *Form1.cs* of a form with a `TextControl` named `textControl1`, such as the one of [Create Your First Windows Forms Application](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/getting-started/document-editor/first-application/llms-full.txt).

### How Track Changes Works

While tracking is on, the editor records each change as a *tracked change*, marks it and assigns it to the current user. Inserted text is shown in color, deleted text in color and struck through. The color depends on the author; changes of the current user are red by default.

A tracked change stays in the document until someone accepts or rejects it. Accepting keeps the change and removes the mark. Rejecting undoes it: inserted text is removed and deleted text comes back. Turning tracking off only stops the recording of new changes; changes already recorded stay marked.

Tracked changes are saved with the document and loaded again in the TX Text Control format (TX), RTF, DOC and DOCX. Changes that MS Word recorded in a DOCX file appear in the editor as tracked changes as well.

Some complex operations can't be tracked, for example deleting a table column or merging table cells. In this case, the editor asks the user in a message box whether to make the change anyway. [Handle Changes That Can't Be Tracked](#handle-changes-that-can-t-be-tracked) shows how to decide this in code.

### Review Changes in the Ribbon

The **Proofing** tab of the ribbon, a [RibbonProofingTab](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-windows-forms-ribbon/ribbonproofingtab/llms-full.txt), has a **Track Changes** group. Its **Track Changes** button turns tracking on and off, **Accept** and **Reject** handle the current change or all changes, and **Previous** and **Next** move between the changes. The **Tracked Changes** split button opens the Tracked Changes sidebar, which lists every change with its kind, text, author and time:

![TX Text Control Words with inserted text shown in red and underlined, and the Tracked Changes sidebar on the right listing one Text Inserted change by the user John with date and time.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/tracked-changes-sidebar.551f2009.webp)

The button needs a sidebar to open. Connect one with the [TrackedChangesSidebar](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-windows-forms-ribbon/ribbonproofingtab/trackedchangessidebar-property/llms-full.txt) property of the tab, in the **Properties** window or in code, as [Sidebar and Panels](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/ribbon-ui/sidebar/llms-full.txt) describes. [Create a Ribbon Application with Sidebar Support](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/getting-started/document-editor/ribbon-sidebar/llms-full.txt) sets up such a form step by step.

Without a ribbon, the [TrackedChangesDialog](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchangesdialog/llms-full.txt) shows the same list in a modeless dialog box, in which the user jumps to a change and accepts or rejects it:

```csharp
private void trackedChangesDialogButton_Click(object sender, EventArgs e)
{
    TrackedChangesDialog dialog = new TrackedChangesDialog(textControl1);
    dialog.Show();
}
```

### Set the Author and Turn On Tracking

The author of a change is the current user: the first name in [UserNames](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/usernames-property/llms-full.txt). When the list is empty, changes are recorded for an unknown user. [IsTrackChangesEnabled](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/istrackchangesenabled-property/llms-full.txt) turns tracking on and off.

The following code sets both when the form opens:

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

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        Load += Form1_Load;
    }

    private void Form1_Load(object sender, EventArgs 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;
    }
}
```

Keep the `namespace` that Visual Studio created around the class. Set `UserNames` from the signed-in user of your application, so that each change shows who made it. The same list decides who may edit which regions of a protected document, as [Document Protection and Editable Regions](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/protection/llms-full.txt) explains.

### List the Tracked Changes

[TrackedChanges](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/trackedchanges-property/llms-full.txt) returns a [TrackedChangeCollection](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchangecollection/llms-full.txt) with the changes of the text part that has the input focus: the main text, a header, a footer or a text frame. [TextParts](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/textparts-property/llms-full.txt) returns all text parts, each an [IFormattedText](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/iformattedtext/llms-full.txt) with a `TrackedChanges` collection of its own. The following button handler shows all changes in a message box:

```csharp
private void listChangesButton_Click(object sender, EventArgs e)
{
    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");
}
```

Each [TrackedChange](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchange/llms-full.txt) describes one change:

- [ChangeKind](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchange/changekind-property/llms-full.txt) is `InsertedText` or `DeletedText`.
- [UserName](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchange/username-property/llms-full.txt) is the author, `null` or an empty string for an unknown user.
- [ChangeTime](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchange/changetime-property/llms-full.txt) is the date and time of the change, in Coordinated Universal Time (UTC).
- [Text](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchange/text-property/llms-full.txt) is the changed text, and [Start](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchange/start-property/llms-full.txt) and [Length](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchange/length-property/llms-full.txt) give its position. `Start` is one-based, unlike the zero-based positions of a selection.
- [Number](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchange/number-property/llms-full.txt) counts the changes in the order of the text, starting at 1. The [indexer](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchangecollection/item-property/llms-full.txt) of the collection takes this number.

### Accept and Reject Changes

[TrackedChangeCollection.Remove](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchangecollection/remove-method/llms-full.txt) is the only way to remove a tracked change: with `true`, it accepts the change, with `false`, it rejects it. [GetItem](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchangecollection/getitem-method/llms-full.txt) without a parameter returns the change at the input position, or `null`:

```csharp
private void acceptButton_Click(object sender, EventArgs 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` accepts the change the user has clicked into.
- `RemoveAllChanges(true)` accepts all changes of the text part, and `RemoveAllChanges(false)` rejects them. It takes the first change until none is left, because each removal renumbers the rest. `Remove` returns `false` if a change can't be removed, which ends the loop.

### Move Through the Changes

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

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

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

### Handle Changes That Can't Be Tracked

Before an operation that can't be tracked, the editor raises [CannotTrackChange](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/cannottrackchange-event/llms-full.txt). Without a handler, a message box asks the user. The handler receives [CannotTrackChangeEventArgs](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/cannottrackchangeeventargs/llms-full.txt) and can decide itself. The following handler never allows a change that would not be tracked:

```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;
}
```

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

Connect the handler in the **Properties** window: select `textControl1`, click the **Events** button and double-click **CannotTrackChange**. Or connect it in code with `textControl1.CannotTrackChange += textControl1_CannotTrackChange;` in the constructor after `InitializeComponent`.

### React to Tracked Changes

The `TextControl` raises four events for tracked changes. Each handler receives [TrackedChangeEventArgs](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchangeeventargs/llms-full.txt), whose [TrackedChange](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchangeeventargs/trackedchange-property/llms-full.txt) property is the change:

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

The following handler shows the latest change in the title bar of the form:

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

[Events](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/events/llms-full.txt) explains how event handlers are connected and lists the other events of the editor.

### Change How Changes Are Highlighted

A `TrackedChange` has properties for its appearance:

- [HighlightColor](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchange/highlightcolor-property/llms-full.txt) is a `System.Drawing.Color`. When it is [DefaultHighlightColor](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchange/defaulthighlightcolor-property/llms-full.txt), changes of other users get a color that depends on the user name.
- [HighlightMode](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchange/highlightmode-property/llms-full.txt) is `HighlightMode.Always` or `HighlightMode.Never`.
- [Active](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/trackedchange/active-property/llms-full.txt) set to `false` deactivates a change: it is no longer highlighted, and `GetItem` skips it.

To process the tracked changes of a whole document in one step, for example to accept the changes of one reviewer in every text part or to accept all changes before a final version is saved, see [Comments and Tracked Changes](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/comments-changes/llms-full.txt). A `ServerTextControl` has the same collections for documents that no user opens. 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 such changes by author, kind and date.

### Next Steps

- [Comments](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/comments/llms-full.txt): add, answer and remove comments during a review.
- [Document Protection and Editable Regions](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/protection/llms-full.txt): protect a document and let users edit only their regions.
- [Sidebar and Panels](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/ribbon-ui/sidebar/llms-full.txt): show the Tracked Changes and Comments panels.
- [Events](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/events/llms-full.txt): connect handlers to the events of the editor.

---

## Nearby

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