Track Changes in Word Documents in C# and VB.NET

You can use the Track Changes feature to monitor all the changes in a Word document. It stores the records of the author, name, and time for each action someone does in a document, such as adding text, deleting it, or modifying it somehow.

GemBox.Document has support for working with changes (revisions) in a document. You can accept or reject a modification, create a new one, edit, or get the revision information.

The following example shows how you can accept or reject all revisions in a Word document programmatically, in C# and VB.NET.

Word document with accepted changes
Screenshot of Word file with accepted changes
using System;
using GemBox.Document;

class Program
{
    static void Main()
    {
        // If using the Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY");

        var document = DocumentModel.Load("%#Revisions.docx%");
        var acceptRevisions = %AcceptRevisions%;

        if (acceptRevisions)
            document.Revisions.AcceptAll();
        else
            document.Revisions.RejectAll();

        document.Save("Revised Document.%OutputFileType%");
    }
}
Imports System
Imports GemBox.Document

Module Program

    Sub Main()

        ' If using the Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY")

        Dim document = DocumentModel.Load("%#Revisions.docx%")
        Dim acceptRevisions = %AcceptRevisions%

        If acceptRevisions Then
            document.Revisions.AcceptAll()
        Else
            document.Revisions.RejectAll()
        End If

        document.Save("Revised Document.%OutputFileType%")
    End Sub
End Module

Accepting/rejecting individual revisions

Besides accepting or rejecting all revisions in a document, you can access individual modifications and accept or reject them based on their properties.

The next example shows accepting and rejecting revisions based on their properties.

using System;
using GemBox.Document;
using GemBox.Document.Tracking;

class Program
{
    static void Main()
    {
        // If using the Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY");

        var document = DocumentModel.Load("%#Revisions.docx%");

        // Iterate through all runs in the document.
        foreach (Run run in document.GetChildElements(true, ElementType.Run))
        {
            // Reject revision of the character format.
            if (run.CharacterFormatRevision != null)
                run.CharacterFormatRevision.Reject();

            // Reject deletion of a run.
            if (run.Revision?.RevisionType == RevisionType.Delete)
                run.Revision.Reject();
        }

        // Iterate through all remaining revisions in the document.
        foreach (var revision in document.Revisions)
        {
            // Accept only revisions from GemBox that were added last month.
            if (revision.Author == "GemBox" && revision.Date > DateTime.Now.AddMonths(-1))
                revision.Accept();
        }

        document.Save("Processed Revisions.%OutputFileType%");
    }
}
Imports System
Imports GemBox.Document
Imports GemBox.Document.Tracking

Module Program

    Sub Main()

        ' If using the Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY")

        Dim document = DocumentModel.Load("%#Revisions.docx%")

        ' Iterate through all runs in the document.
        For Each run As Run in document.GetChildElements(true, ElementType.Run)
            ' Reject revision of the character format.
            If run.CharacterFormatRevision IsNot Nothing
                run.CharacterFormatRevision.Reject()
            End If

            ' Reject deletion of a run.
            If run.Revision?.RevisionType = RevisionType.Delete Then
                run.Revision.Reject()
            End If
        Next

        ' Iterate through all remaining revisions in the document.
        For Each revision in document.Revisions
            ' Accept only revisions from GemBox that were added last month.
            If revision.Author = "GemBox" And revision.Date > DateTime.Now.AddMonths(-1) Then
                revision.Accept()
            End If
        Next

        document.Save("Processed Revisions.%OutputFileType%")

    End Sub
End Module

Creating revisions

Even though GemBox.Document doesn't have support for tracking changes automatically, it has an API that allows you to create revisions programmatically. You can find more information about revision related members in the Tracking namespace.

The example below shows how you can track changes in an updated document.

Word document with added revisions
Screenshot of Word file with added revisions
using System;
using GemBox.Document;
using GemBox.Document.Tables;
using GemBox.Document.Tracking;

class Program
{
    static void Main()
    {
        // If using the Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY");

        var document = DocumentModel.Load("%#NoRevisions.docx%");
        var section = document.Sections[0];

        var paragraph1 = section.Blocks.Cast<Paragraph>(0);
        var run1 = paragraph1.Inlines.Cast<Run>(0);

        // 1. Changing the formatting of the run.
        var characterFormatRevision = new CharacterFormatRevision(document)
        {
            Author = "GemBox",
            Date = DateTime.Now
        };
        // CharacterFormatRevision.CharacterFormat holds the format which was used before the revision was applied.
        characterFormatRevision.CharacterFormat = run1.CharacterFormat.Clone();
        run1.CharacterFormatRevision = characterFormatRevision;
        // Changing the format.
        run1.CharacterFormat.UnderlineStyle = UnderlineType.Double;

        // 2. Removing the run.
        var run2 = paragraph1.Inlines.Cast<Run>(1);
        // Mark run as deleted.
        run2.Revision = new Revision(RevisionType.Delete) { Author = "GemBox" };

        // 3. Inserting a run.
        var run3 = new Run(document, "Run3");
        // Mark run as inserted.
        run3.Revision = new Revision(RevisionType.Insert) { Author = "GemBox" };
        paragraph1.Inlines.Add(run3);

        // 4. Joining paragraphs.
        var paragraph2 = section.Blocks.Cast<Paragraph>(1);
        // Marking paragraph as deleted doesn't remove the paragraph content, it joins it with the following paragraph.
        paragraph2.Revision = new Revision(RevisionType.Delete) { Author = "GemBox" };

        var table = section.Blocks.Cast<Table>(3);

        // 5. Removing a table row.
        var row2 = table.Rows[1];
        // Mark row as deleted.
        row2.Revision = new Revision(RevisionType.Delete) { Author = "GemBox" };

        // 6. Adding a new table row.
        var newRow = new TableRow(document,
            new TableCell(document, new Paragraph(document, "new row")),
            new TableCell(document));
        // Mark row as inserted.
        newRow.Revision = new Revision(RevisionType.Insert) { Author = "GemBox" };
        table.Rows.Add(newRow);

        document.Save("Added Revisions.%OutputFileType%");
    }
}
Imports System
Imports GemBox.Document
Imports GemBox.Document.Tables
Imports GemBox.Document.Tracking

Module Program

    Sub Main()

        ' If using the Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY")

        Dim document = DocumentModel.Load("%#NoRevisions.docx%")
        Dim section = document.Sections(0)

        Dim paragraph1 = section.Blocks.Cast(Of Paragraph)(0)
        Dim run1 = paragraph1.Inlines.Cast(Of Run)(0)

        ' 1. Changing the formatting of the run.
        Dim characterFormatRevision = New CharacterFormatRevision(document) With
        {
            .Author = "GemBox",
            .Date = System.DateTime.Now
        }
        ' CharacterFormatRevision.CharacterFormat holds the format which was used before the revision was applied.
        characterFormatRevision.CharacterFormat = run1.CharacterFormat.Clone()
        run1.CharacterFormatRevision = characterFormatRevision
        ' Changing the format.
        run1.CharacterFormat.UnderlineStyle = UnderlineType.Double

        ' 2. Removing the run.
        Dim run2 = paragraph1.Inlines.Cast(Of Run)(1)
        ' Mark run as deleted.
        run2.Revision = New Revision(RevisionType.Delete) With {.Author = "GemBox"}

        ' 3. Inserting a run.
        Dim run3 = New Run(document, "Run3")
        ' Mark run as inserted.
        run3.Revision = New Revision(RevisionType.Insert) With {.Author = "GemBox"}
        paragraph1.Inlines.Add(run3)

        ' 4. Joining paragraphs.
        Dim paragraph2 = section.Blocks.Cast(Of Paragraph)(1)
        ' Marking paragraph as deleted doesn't remove the paragraph content, it joins it with the following paragraph.
        paragraph2.Revision = New Revision(RevisionType.Delete) With {.Author = "GemBox"}
        Dim table = section.Blocks.Cast(Of Table)(3)

        ' 5. Removing a table row.
        Dim row2 = table.Rows(1)
        ' Mark row as deleted.
        row2.Revision = New Revision(RevisionType.Delete) With {.Author = "GemBox"}

        ' 6. Adding a new table row.
        Dim newRow = New TableRow(document,
            New TableCell(document, New Paragraph(document, "new row")),
            New TableCell(document))
        ' Mark row as inserted.
        newRow.Revision = New Revision(RevisionType.Insert) With {.Author = "GemBox"}
        table.Rows.Add(newRow)

        document.Save("Added Revisions.%OutputFileType%")

    End Sub
End Module

See also


Next steps

GemBox.Document is a .NET component that enables you to read, write, edit, convert, and print document files from your .NET applications using one simple API. How about testing it today?

Download Buy