Bookmarks are very useful in developing and working with documents. Besides content controls, they are the main tool for our Word add-in project and are used as placeholders to mark items or locations in the Word document. Although developers would like bookmarks to have more options and operations like content controls, they are just not as flexible. Some options that could be supported by VSTO 3 but, unfortunately are not, could make our lives as developers easier:
- before delete and after add events,
- locking bookmark to prevent deleting,
- locking bookmark and its content,
- deleting bookmark with its content…
All these options are supported for content controls.
This post is about a problem that exists when user deletes a bookmark from the document manually. There is no event triggered when this happens. Deleting bookmarks manually causes its Interop.Word.Bookmark object to be removed, but Tools.Word.Bookmark object remains in the documents controls collection. We can access this remaining object but access to its properties and methods will throw exception with message "Object has been deleted". In this state it can not even be removed from the document.Controls collection. So if user removes the bookmark manually, our application will be unaware of that and will break when trying to access its properties, methods or even to remove it.
Fortunately, there is a way to “repair” this broken Tools.Word.Bookmark object enough for us be able to remove it from the collection of document’s VSTO objects. Then we are able to recover our application from this unwanted user action. Every time we want to get any bookmarks we use the following method:
Public Function GetBookmarkIfExists(ByVal bookmarkName As String) _
Dim returningControl As Tools.Word.Bookmark = Nothing
' If bookmark exists in word document, get it:
If Me.Controls.Contains(bookmarkName) Then
returningControl = Me.Controls(bookmarkName)
' If user has deleted bookmark manually, VSTO object exists but interop
' not. To recover from this unwanted state it is needed to remove VSTO
' object too:
If (Not (Globals.ThisDocument.Bookmarks.Exists(bookmarkName))) Then
Globals.ThisDocument.Bookmarks.Add(bookmarkName, Me.Range(0, 0))
' Remove all bindings from the bookmark and delete it:
returningControl = Nothing
The method is in the document class.
This method checks if the corresponding Interop object exists for the VSTO object. If not, the VSTO object it broken. By adding interop object with the same name, VSTO object will be “repaired”. Range of repaired bookmark will not be as it was before removal but it is deletable now. Deleting bookmark will not delete its content.
Of course this method needs to be adapted to your code and application.