# Track Changes

> Turn on track changes in VB6, list tracked insertions and deletions, accept or reject them and build a review dialog box like the TXWords sample's.

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

---

When several people work on a contract or a report, each of them wants to see what the others changed before accepting it. With track changes turned on, `TXTextControl` keeps every insertion and deletion in the document as a *tracked change*, marked up on the screen with the name of the user who made it and the time, until someone accepts or rejects it.

Track changes is available since TX Text Control ActiveX 26.0. The Visual Basic 6 code below turns tracking on, walks through the tracked changes of a document and accepts or rejects them, much like the **Review Changes** dialog box of the TXWords sample program does.

### How Track Changes Works

The [IsTrackChangesEnabled](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/istrackchangesenabled-property/llms-full.txt) property switches tracking on and off. By default it is `False`. While it is `True`, the control marks up each new change of the text:

- **Kinds of changes.** A tracked change is either inserted text or deleted text. Inserted text is shown in color, deleted text in color and struck through. The color depends on the user; the default color for the current user is red.
- **User and time.** Each change belongs to a user and has a time stamp. The user is the current user, the first name of the list that the [UserNames](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/usernames-property/llms-full.txt) property holds. When the list is empty, the user name is an empty string, which stands for an unknown user.
- **Identifiers.** Every tracked change has a numeric identifier of the data type `Long`. All members that read or remove a change take this identifier.
- **Removing changes.** A tracked change stays in the document until it is accepted or rejected. Turning tracking off stops the control from marking up new changes, but the changes that are already tracked remain.
- **File formats.** Tracked changes are saved and loaded with the TX Text Control format (TX), RTF and the Microsoft Word formats DOC and DOCX. Loading a document that contains tracked changes creates them in the control.

![A tracked insertion, shown in red and underlined, and a tracked deletion, shown in red and struck through, in a TXTextControl document.](https://docs.textcontrol.com/assets/img/tx-text-control-activex/tracked-changes-document.1abbb237.webp)

Some complex changes of a table's layout, such as deleting a table column or merging table cells, cannot be tracked. For these, the control asks the user whether to make the change anyway; [Handle Changes That Cannot Be Tracked](#handle-changes-that-cannot-be-tracked) shows how to take over that decision.

### Turn Track Changes On and Off

In TXWords, the **Edit** menu has a **Reviewing** submenu with the **Track Changes** item. Its handler flips the check mark and sets `IsTrackChangesEnabled` to match:

```vbscript
Private Sub mnuEdit_Reviewing_TrackChanges_Click()
    mnuEdit_Reviewing_TrackChanges.Checked = Not mnuEdit_Reviewing_TrackChanges.Checked
    TXTextControl1.IsTrackChangesEnabled = mnuEdit_Reviewing_TrackChanges.Checked
End Sub
```

When the **Edit** menu opens, TXWords sets the check mark from the property, so the menu shows the current state, and enables **Review Changes** only when the document contains a tracked change:

```vbscript
mnuEdit_Reviewing_TrackChanges.Checked = TXTextControl1.IsTrackChangesEnabled
mnuEdit_Reviewing_ReviewChanges.Enabled = (TXTextControl1.TrackedChangeNext(0) <> 0)
```

![The TXWords Edit menu with the Reviewing submenu open, where Track Changes is checked above Review Changes and Comments.](https://docs.textcontrol.com/assets/img/tx-text-control-activex/reviewing-menu.ac5a75e3.webp)

`IsTrackChangesEnabled` can also be set at design time in the Properties window of Visual Basic.

### Set the Name of the Reviewer

A tracked change takes its user name from the first entry of `UserNames`. The property is a string in which the names are separated by a `|` character. Set it before the user starts editing, for example in `Form_Load`:

```vbscript
Private Sub Form_Load()
    ' The first name is the current user
    TXTextControl1.UserNames = "Jane Smith"
    TXTextControl1.IsTrackChangesEnabled = True
End Sub
```

Every change typed after this code runs is tracked with the name *Jane Smith*. `UserNames` can be set at run time only. It also decides which users may edit which parts of a protected document, which [Document Protection](https://docs.textcontrol.com/tx-text-control-activex/document-editor/protection/llms-full.txt) describes.

### List the Tracked Changes

The [TrackedChangeNext](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangenext-method/llms-full.txt) method enumerates the tracked changes in the order of the text. Called with zero, it returns the identifier of the first change; called with an identifier, it returns the one that follows. It returns zero when there are no more changes.

The following procedure prints each change to the Immediate window of Visual Basic:

```vbscript
Private Sub ListTrackedChanges()
    Dim id As Long
    Dim kind As String
    Dim reviewer As String

    id = TXTextControl1.TrackedChangeNext(0)
    Do While id <> 0
        ' 1 is inserted text, 2 is deleted text
        If TXTextControl1.TrackedChangeKind(id) = 1 Then
            kind = "Inserted"
        Else
            kind = "Deleted"
        End If
        reviewer = TXTextControl1.TrackedChangeUserName(id)
        If reviewer = "" Then reviewer = "Unknown Reviewer"
        Debug.Print reviewer & " " & kind & " characters " & _
            TXTextControl1.TrackedChangeStart(id) & " to " & _
            TXTextControl1.TrackedChangeEnd(id) & _
            " (" & TXTextControl1.TrackedChangeTime(id) & ")"
        id = TXTextControl1.TrackedChangeNext(id)
    Loop
End Sub
```

The code works as follows:

- [TrackedChangeKind](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangekind-property/llms-full.txt) returns 1 for inserted text and 2 for deleted text.
- [TrackedChangeUserName](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangeusername-property/llms-full.txt) returns the name of the user who made the change, or an empty string for an unknown user. TXWords shows "Unknown Reviewer" in this case.
- [TrackedChangeStart](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangestart-property/llms-full.txt) and [TrackedChangeEnd](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangeend-property/llms-full.txt) return the first and the last character of the change as one-based indexes.
- [TrackedChangeTime](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangetime-property/llms-full.txt) returns the date and time of the change as a `Date` in Coordinated Universal Time (UTC).

These four properties are read-only and available at run time only.

### Select a Tracked Change

To show a change to the user, select its text. The [SelStart](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/selstart-property/llms-full.txt) property counts from 0, while `TrackedChangeStart` and `TrackedChangeEnd` count from 1, so TXWords subtracts 1 from both:

```vbscript
Private Sub SelectTrackedChange(ByVal changeId As Long)
    Dim posStart As Long
    Dim posEnd As Long

    posStart = TXTextControl1.TrackedChangeStart(changeId) - 1
    posEnd = TXTextControl1.TrackedChangeEnd(changeId) - 1
    TXTextControl1.SelStart = posStart
    TXTextControl1.SelLength = posEnd - posStart + 1
End Sub
```

[SelLength](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/sellength-property/llms-full.txt) is the number of selected characters, which is the distance between the two positions plus one.

### Accept and Reject Changes

The [TrackedChangeDelete](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangedelete-method/llms-full.txt) method is the only way to remove a tracked change. Its second parameter decides what happens to the text:

- **`True` accepts the change.** The markup is removed and the text stays as it is.
- **`False` rejects the change.** Inserted text is removed and deleted text is inserted again.

The method returns `True` when the change could be removed. To accept or reject every change, TXWords asks for the first change again after each call, because the removed change no longer has a successor:

```vbscript
Private Sub DeleteAllTrackedChanges(ByVal accept As Boolean)
    Dim id As Long
    Do
        id = TXTextControl1.TrackedChangeNext(0)
        If id <> 0 Then TXTextControl1.TrackedChangeDelete id, accept
    Loop While id <> 0
End Sub
```

Call `DeleteAllTrackedChanges True` to accept all changes and `DeleteAllTrackedChanges False` to reject them.

### Build a Review Dialog Box

The **Review Changes** dialog box of TXWords, in *frmReviewTrackedChanges.frm*, combines the procedures above. **Edit** > **Reviewing** > **Review Changes** opens it as a modal form, after checking that `TrackedChangeNext(0)` is not zero; otherwise, a message box says that the document does not contain any tracked changes. The dialog box works like this:

- **The current change.** On loading, the form takes the first change with `TrackedChangeNext(0)`, selects its text in the document and shows the user name and the kind above a preview and the time below it.
- **The preview.** The form holds a second `TXTextControl` with its [EditMode](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/editmode-property/llms-full.txt) set to 2 (read only). The form copies the selected text of the document into it with [SaveToMemory](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/savetomemory-method/llms-full.txt) and [LoadFromMemory](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/loadfrommemory-method/llms-full.txt), and copies the `UserNames` of the document too.
- **The buttons.** **Accept** and **Reject** call `TrackedChangeDelete` for the current change and go to the next one; the form closes when none is left. **Accept All** and **Reject All** run the loop of the previous section. **Next** moves on without a decision, and starts at the first change again after the last one.

![The Review Changes dialog box of TXWords showing an inserted text of an unknown reviewer with its time stamp and the buttons Next, Accept, Reject, Accept All, Reject All and Close.](https://docs.textcontrol.com/assets/img/tx-text-control-activex/review-changes-form.21cbfa1c.webp)

This is how the form fills the preview:

```vbscript
Dim data() As Byte
data = tx.SaveToMemory(8, True)
txChange.LoadFromMemory data, 8
```

`tx` is the `TXTextControl` of the main form, which the menu handler passes to the dialog box, and `txChange` is the preview control. Format 8 is the internal Text Control format with Unicode text, and the second parameter `True` of `SaveToMemory` saves only the current selection.

### Handle Changes That Cannot Be Tracked

When the user makes a change that cannot be added to the list of tracked changes, such as deleting a table column, the [CannotTrackChange](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/cannottrackchange-event/llms-full.txt) event occurs. By default, the control then shows a message box that asks the user whether to make the change.

To decide in code, set the `Handled` parameter to `True`, which suppresses the message box, and set `Cancel` to `False` to make the change or to `True` to cancel it. The following handler refuses all such changes without asking:

```vbscript
Private Sub TXTextControl1_CannotTrackChange(Cancel As Boolean, Handled As Boolean)
    ' Keep the document unchanged and skip the default message box
    Cancel = True
    Handled = True
End Sub
```

`Cancel` is `True` by default, so leaving it unchanged and setting only `Handled` has the same effect.

### React to Tracked Changes

Three events report changes of the list of tracked changes. Each passes the identifier of the change:

- [TrackedChangeCreated](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangecreated-event/llms-full.txt) occurs when a change has been tracked, and also for each tracked change of a document that is being loaded.
- [TrackedChangeChanged](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangechanged-event/llms-full.txt) occurs when the text of a tracked change has been altered.
- [TrackedChangeDeleted](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangedeleted-event/llms-full.txt) occurs when a change has been accepted or rejected.

The following handler updates a label on the form with the name of the user who made the latest change:

```vbscript
Private Sub TXTextControl1_TrackedChangeCreated(ByVal TrackedChangeId As Long)
    lblLastChange.Caption = "Last change by " & _
        TXTextControl1.TrackedChangeUserName(TrackedChangeId)
End Sub
```

`lblLastChange` is a `Label` control that you add to the form.

### Key Members

| Member | Description |
|---|---|
| [IsTrackChangesEnabled](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/istrackchangesenabled-property/llms-full.txt) | Turns tracking of new changes on or off. |
| [UserNames](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/usernames-property/llms-full.txt) | Holds the list of users; the first name is the user of new changes. |
| [TrackedChangeNext](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangenext-method/llms-full.txt) | Returns the identifier of the first or the next tracked change. |
| [TrackedChangeKind](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangekind-property/llms-full.txt) | Returns whether a change is inserted or deleted text. |
| [TrackedChangeStart](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangestart-property/llms-full.txt), [TrackedChangeEnd](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangeend-property/llms-full.txt) | Return the first and the last character of a change. |
| [TrackedChangeUserName](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangeusername-property/llms-full.txt), [TrackedChangeTime](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangetime-property/llms-full.txt) | Return the user and the UTC time of a change. |
| [TrackedChangeDelete](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangedelete-method/llms-full.txt) | Accepts or rejects a change and removes it. |
| [CannotTrackChange](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/cannottrackchange-event/llms-full.txt) | Occurs for a change that cannot be tracked. |
| [TrackedChangeCreated](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangecreated-event/llms-full.txt), [TrackedChangeChanged](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangechanged-event/llms-full.txt), [TrackedChangeDeleted](https://docs.textcontrol.com/tx-text-control-activex/reference/txtextcontrol/trackedchangedeleted-event/llms-full.txt) | Occur when a change is created, altered or removed. |

The programming category [Tracking Document Changes](https://docs.textcontrol.com/tx-text-control-activex/reference/categories/track-changes/llms-full.txt) lists all members for tracked changes.

### Related Pages

- [Comments](https://docs.textcontrol.com/tx-text-control-activex/document-editor/comments/llms-full.txt): notes and replies attached to text, the other half of a review.
- [Document Protection](https://docs.textcontrol.com/tx-text-control-activex/document-editor/protection/llms-full.txt): the user list of `UserNames`, edit modes and editable regions.
- [A Word Processor](https://docs.textcontrol.com/tx-text-control-activex/document-editor/word-processor/llms-full.txt): the TXWords sample program that contains the review dialog box.
- [Version 26.0](https://docs.textcontrol.com/tx-text-control-activex/whats-new/older-versions/2600/llms-full.txt): the release that introduced track changes.

---

## Nearby

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