Hi there,
I am having a problem updating bookmarks, using .NET 6 and Gembox.Document 35.0.1443.
Let me explain my use case.
My Word document needs to be alternately editable by the application and by a user making changes directly:
- The application creates the document based on a template, adds paragraphs/tables, each delimited by a bookmark, and saves the document.
- The user can then open the document, add paragraphs and save again.
- If necessary, the application can open the latest version of the document, look up the bookmarks and update the paragraphs/tables.
- The user can then continue working and so on.
Problem
Multiple bookmark updates are successful as long as no paragraphs are added by the user.
The bookmarks consisting of several blocks seem to have problems. The BookmarkEnd disappears and the next update throws an error (I added some colours to distinguish between BookmarkStart and BookmarkEnd).
Demo application
Below is a test console application. Type ‘1’ to create the document, type ‘2’ to update. Edit the file between updates to replicate the error.
Program.cs
using BookmarkUpdate;
Console.WriteLine("Bookmark test application");
var updateCycle = 0;
while (true)
{
if (int.TryParse(Console.ReadLine(), out int x))
{
if (x == 1)
{
Export.Create();
Console.WriteLine("Test document with bookmarks created");
}
if (x == 2)
{
updateCycle++;
Export.Update(updateCycle);
Console.WriteLine("Bookmarks updated");
}
}
}
Export.cs
using GemBox.Document;
using GemBox.Document.Tables;
namespace BookmarkUpdate
{
public static class Export
{
public static void Create()
{
ComponentInfo.SetLicense("FREE-LIMITED-KEY");
var document = new DocumentModel();
var firstBookmarkName = "FirstBookmark";
var secondBookmarkName = "SecondBookmark";
var thirdBookmarkName = "ThirdBookmark";
var fourthBookmarkName = "FourthBookmark";
document.Sections.Add(
new Section(document,
new Paragraph(document, new Run(document, "")),
new Paragraph(document,
new BookmarkStart(document, firstBookmarkName),
new Run(document, "This is a first bookmark."),
new BookmarkEnd(document, firstBookmarkName)
) { ParagraphFormat = {BackgroundColor = Color.Yellow}},
new Paragraph(document, new Run(document, "")),
new Paragraph(document, new BookmarkStart(document, secondBookmarkName)) { ParagraphFormat = { BackgroundColor = Color.Green } },
new Paragraph(document, new Run(document, "This is a second bookmark.")),
new Paragraph(document, new BookmarkEnd(document, secondBookmarkName)) { ParagraphFormat = { BackgroundColor = Color.Red } },
new Paragraph(document, new Run(document, "")),
new Paragraph(document,new BookmarkStart(document, thirdBookmarkName)) { ParagraphFormat = { BackgroundColor = Color.Green } },
new Table(document, 2, 1, (r, c) => new TableCell(document, new Paragraph(document, $"Original Item {r}-{c}"))),
new Paragraph(document, new BookmarkEnd(document, thirdBookmarkName)) { ParagraphFormat = { BackgroundColor = Color.Red } },
new Paragraph(document, new Run(document, "")),
new Paragraph(document,
new BookmarkStart(document, fourthBookmarkName),
new Run(document, "This is a fourth bookmark."),
new BookmarkEnd(document, fourthBookmarkName)
) { ParagraphFormat = { BackgroundColor = Color.Yellow } },
new Paragraph(document, new Run(document, ""))
)
);
document.Save("BookmarkUpdate.docx");
}
public static void Update(int updateCycleNumber)
{
ComponentInfo.SetLicense("FREE-LIMITED-KEY");
var document = DocumentModel.Load("BookmarkUpdate.docx");
var firstBookmarkName = "FirstBookmark";
var secondBookmarkName = "SecondBookmark";
var thirdBookmarkName = "ThirdBookmark";
var fourthBookmarkName = "FourthBookmark";
var updatedFirst = $"Updated first bookmark, cycle {updateCycleNumber}.";
document.Bookmarks[firstBookmarkName].GetContent(false).LoadText(updatedFirst);
var updatedSecond = new Paragraph(document, new Run(document, $"This is an updated second bookmark, cycle {updateCycleNumber}."));
document.Bookmarks[secondBookmarkName].GetContent(false).Set(updatedSecond.Content);
var table = new Table(document, 2, 1, (r, c) => new TableCell(document, new Paragraph(document, $"Updated Item {r}-{c}, cycle {updateCycleNumber}")));
document.Bookmarks[thirdBookmarkName].GetContent(false).Set(table.Content);
var updatedFourth = new Paragraph(document, new Run(document, $"This is an updated fourth bookmark, cycle {updateCycleNumber}."));
ContentRange range = document.Bookmarks[fourthBookmarkName].GetContent(false);
range.LoadText("Test:");
range.End.InsertRange(updatedFourth.Content);
document.Save("BookmarkUpdate.docx");
}
}
}
Document output without changes made by the user:
After creation, I get the following output:
- yellow = BookmarkStart and BookmarkEnd on same paragraph
- green = paragraph with single BookmarkStart
- red = paragraph with single BookmarkEnd
After first application update, without user changes, no more red paragraphs.
As long as the user doesn’t make any changes, multiple updates are possible.
Document output with changes made by the user:
However, if the user makes a manual change and adds a paragraph after creation, it won’t work:
The user added some text on the first not bookmarked paragraph:
After first application update, one red paragraph is gone, output of table is wrong:
During the second application update, the broken bookmark is no longer found and the application crashes:
document.Bookmarks[secondBookmarkName].GetContent(false).Set(updatedSecond.Content);
System.NullReferenceException: ‘Object reference not set to an instance of an object.’
GemBox.Document.BookmarkCollection.this[string].get returned null.
Any ideas on what I am doing wrong?
What is the best solution for my use case?
Kind regards,
Christophe