PRB: CodeModelEvents not firing events in a Visual Studio add-in

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio 2005
Date: March 2008   Microsoft Visual Studio 2008
Updated: March 2013   Microsoft Visual Studio 2010
      Microsoft Visual Studio 2012

This article explains why the EnvDTE80.CodeModelEvents class does not fire the ElementAdded, etc. events.

More Information

Visual Studio 2005 introduced the new EnvDTE80 namespace which provides the EnvDTE80.CodeModelEvents class with the ElementAdded, ElementChanged and ElementDeleted events. To get an instance of this class, you have to cast the DTE2.Events property to the EnvDTE80.Events2 type, which provides the CodeModelEvents property. However, when you do this and test it adding a function to a class, the ElementAdded event is not fired. This is due to an optimization performed by the Visual Studio team: to avoid firing events each time that the code model changes (which can be really often) when maybe nobody is listening to them, events are not fired unless you have traversed the code elements before subscribing to the event. The add-in below shows the code needed to get code model events of the first project of a solution. If you can load the add-in when a solution is loaded with a project, and add a new function to an existing class, you will notice that you receive the ElementAdded event, but if you remove the NavigateCodeElements function and repeat the test, the event is not fired.
Option Strict On

Imports System
Imports Extensibility
Imports EnvDTE
Imports EnvDTE80
Imports System.Windows.Forms

Public Class Connect
   Implements IDTExtensibility2

   Private m_objDTE2 As DTE2
   Private WithEvents m_objCodeModelEvents As EnvDTE80.CodeModelEvents

   Public Sub OnConnection(ByVal Application As Object, ByVal ConnectMode As Extensibility.ext_ConnectMode, ByVal AddInInst As Object, _
      ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnConnection

      Dim objEvents2 As EnvDTE80.Events2

      Select Case ConnectMode

         Case ext_ConnectMode.ext_cm_AfterStartup, ext_ConnectMode.ext_cm_Startup

            m_objDTE2 = DirectCast(Application, DTE2)

            If m_objDTE2.Solution.Projects.Count > 0 Then


               objEvents2 = DirectCast(m_objDTE2.Events, EnvDTE80.Events2)

               m_objCodeModelEvents = objEvents2.CodeModelEvents

            End If

      End Select

   End Sub

   Private Sub NavigateCodeElements(ByVal colCodeElements As CodeElements)

      For Each objCodeElement As CodeElement In colCodeElements

         If TypeOf objCodeElement Is CodeNamespace Then
            NavigateCodeElements(CType(objCodeElement, CodeNamespace).Members)
         ElseIf TypeOf objCodeElement Is CodeType Then
            NavigateCodeElements(CType(objCodeElement, CodeType).Members)
         End If


   End Sub

   Private Sub m_objCodeModelEvents_ElementAdded(ByVal Element As EnvDTE.CodeElement) Handles m_objCodeModelEvents.ElementAdded
      MessageBox.Show(Element.Name & " added")
   End Sub

   Private Sub m_objCodeModelEvents_ElementChanged(ByVal Element As EnvDTE.CodeElement, ByVal Change As EnvDTE80.vsCMChangeKind) _
      Handles m_objCodeModelEvents.ElementChanged

      MessageBox.Show(Element.Name & " changed: " & Change.ToString)
   End Sub

   Private Sub m_objCodeModelEvents_ElementDeleted(ByVal Parent As Object, ByVal Element As EnvDTE.CodeElement) _
      Handles m_objCodeModelEvents.ElementDeleted

      MessageBox.Show(Element.Name & " removed")
   End Sub

   Public Sub OnAddInsUpdate(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnAddInsUpdate

   End Sub

   Public Sub OnBeginShutdown(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnBeginShutdown

   End Sub

   Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, ByRef custom As System.Array) _
      Implements Extensibility.IDTExtensibility2.OnDisconnection

   End Sub

   Public Sub OnStartupComplete(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnStartupComplete

   End Sub

End Class

Go to the 'Visual Studio Extensibility (VSX)' web site for more articles like this (Articles section)