ICodeFactory Labs

Workaround for VSTO bug: Content control Exiting event handler

by Janko 21. May 2010 02:04

If you have ever worked on some Word add-in where you use content controls, you maybe have encountered problems for which you have no explanations. This post is about one of the known VSTO issues and offers a workaround for it.

 

We were working on Word add-in that uses content controls. Also we needed to process data on entering and exiting a content control.

 

Good thing is that VSTO offers events Entering and Exiting.

Bad thing is that Exiting event has a bug. If you are doing some "simple" process in Exiting event handler it could work fine, but you never know what will happen. Using this event could produce very strange problems, problems which look like they should not have any connections with the event.

 

Several strange problems have occurred for which we were unable to find a solution. So we created different POC projects to reproduce and isolate the bugs and posted them on the Microsoft forum. Shortly the issues were confirmed - one of them as a new VSTO bug (https://connect.microsoft.com/VisualStudio/feedback/details/556456/programatically-deselecting-a-content-control-results-in-a-com-exception?wa=wsignin1.0) and another got recognized as a notorious VSTO bug. After using proposed workaround for notorious bug, both bugs were resolved.

 

The notorious problem manifests itself in following way:

In the document there are two building block content controls:

  1.  POCControl1 and
  2.  POCControl2

On the document startup we are adding Entering and Exiting event handlers to these controls.

-On Entering the control TrackChanges is set to TRUE and old value is remembered.

-On Exiting all changes are confirmed and TrackChanges is returned to the previous version.

Problem occurs in following scenario:

  1. Select POCControl1
  2. Entering event occurs.
  3. Unselect POCControl1.
  4. Exiting event occurs.
  5. PROBLEM: on line
    Me.TrackRevisions = Me._oldTrackRevisionsStatus
    Entering event for POCControl1 occurs (which should not happen). After it finishes, Exiting event continues to run from the specified line.

Even stranger behavior occurs when selecting POCControl1 and then selecting POCControl2. Here is the whole POC code:

 

Public Class ThisDocument

    Private _oldTrackRevisionsStatus As Boolean

    Private Sub ThisDocument_Startup(ByVal sender As Object, _
                                     ByVal e As System.EventArgs) Handles Me.Startup
        AddHandler POCControl1.Entering, AddressOf TextItemSelected
        AddHandler POCControl2.Entering, AddressOf TextItemSelected
        AddHandler POCControl1.Exiting, AddressOf TextItemUnselected
        AddHandler POCControl2.Exiting, AddressOf TextItemUnselected

        POCControl1.Tag = "UPPER control"
        POCControl2.Tag = "LOWER control"
    End Sub

    Public Sub TextItemSelected(ByVal sender As BuildingBlockGalleryContentControl, _
                                ByVal e As ContentControlEnteringEventArgs)
        MsgBox("Select " & sender.Tag & " beggining")

        ' Set track changes:
        _oldTrackRevisionsStatus = Me.TrackRevisions
        Me.TrackRevisions = True

        MsgBox("Select " & sender.Tag & " ending")
    End Sub

    Public Sub TextItemUnselected(ByVal sender As BuildingBlockGalleryContentControl, _
                           ByVal cevent As Tools.Word.ContentControlExitingEventArgs)
        MsgBox("Unselect " & sender.Tag & " beggining")

        If sender.Range.Revisions.Count > 0 Then
            sender.Range.Revisions.AcceptAll()
        End If

        Me.TrackRevisions = Me._oldTrackRevisionsStatus

        MsgBox("Unselect " & sender.Tag & " ending")
    End Sub
End Class

 

Proposed solution:

Do not use Exiting event at all. For example, use Application.WindowSelectionChange event instead, which we did. This event is triggered on every selection change in the active document window, whenever it is manually or programmatically caused. In its handler we are tracking "exiting" from the control.

 

So we removed Exiting event handler and related code from our POC project and added WindowSelectionChange event handler:

 

Private _oldTrackRevisionsStatus As Boolean
    Private selectedControl As Tools.Word.BuildingBlockGalleryContentControl

    Private Sub ThisDocument_Startup(ByVal sender As Object, _
                                     ByVal e As System.EventArgs) Handles Me.Startup
        AddHandler POCControl1.Entering, AddressOf TextItemSelected
        AddHandler POCControl2.Entering, AddressOf TextItemSelected
        
        POCControl1.Tag = "UPPERControl"
        POCControl2.Tag = "LOWERControl"
    End Sub

    Public Sub TextItemSelected(ByVal sender As BuildingBlockGalleryContentControl, _
                                ByVal e As ContentControlEnteringEventArgs)
        MsgBox("Select " & sender.Tag & " beggining")

        selectedControl = sender

        ' Set track changes:
        _oldTrackRevisionsStatus = Me.TrackRevisions
        Me.TrackRevisions = True

        MsgBox("Select " & sender.Tag & " ending")
    End Sub

    
    Public Sub WindowSelectionChange_Handler(ByVal sel As Interop.Word.Selection) _
                                      Handles ThisApplication.WindowSelectionChange
        Dim control As Interop.Word.ContentControl = sel.Range.ParentContentControl
        If selectedControl IsNot Nothing _
         AndAlso (control Is Nothing OrElse control.Tag <> selectedControl.Tag) Then
            MsgBox("Unselect " & selectedControl.Tag & " beggining")

            If selectedControl.Range.Revisions.Count > 0 Then
                selectedControl.Range.Revisions.AcceptAll()
            End If

            Me.TrackRevisions = Me._oldTrackRevisionsStatus

            selectedControl = Nothing

            MsgBox("Unselect ending")
        End If
    End Sub

 

If you have issues with content controls and you are using Exiting event, it is possible that it is the root of your problems. Use WindowSelectionChange event and adapt its handler for your own code. It helped us and might potentially help you get rid of some annoying bugs and unwanted behavior.

Currently rated 1.6 by 56 people

  • Currently 1.642859/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

ICF.Labs | .NET | VSTO

Comments

Add comment


(Will show your Gravatar icon)  

  Country flag


  • Comment
  • Preview
Loading




Contact

Development and Sales
ICodeFactory d.o.o.
Trg Marije Trandafil 24/2
21000 Novi Sad
Serbia, Europe
Phone: +381 (0)21 41 77 08
info[at]icodefactory[dot]com

Headquarter
T.C. Bagljaš, Lok. 11
23000 Zrenjanin
Serbia, Europe

Working hours
Monday - Friday
8am - 4pm (GMT+1)