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.
using GemBox.Document;
using System;
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 GemBox.Document
Imports System
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 GemBox.Document;
using GemBox.Document.Tracking;
using System;
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 GemBox.Document
Imports GemBox.Document.Tracking
Imports System
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 Then
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.
using GemBox.Document;
using GemBox.Document.Tables;
using GemBox.Document.Tracking;
using System;
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 GemBox.Document
Imports GemBox.Document.Tables
Imports GemBox.Document.Tracking
Imports System
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 = 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