HOWTO: Add an event handler from a Visual Studio add-in

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

This article explains how to add programmatically (from an add-in) an event handler to a Windows Forms control.

More Information

To do this you need to use the IEventBindingService and IComponentChangeService of the IDesignerHost of the form. The following add-in, when loaded, adds a Form_Load event handler to the Load event of the active window, assuming that it is a form:
Imports Microsoft.Office.Core
Imports Extensibility
Imports System.Runtime.InteropServices
Imports EnvDTE
Imports System.ComponentModel
Imports System.ComponentModel.Design

<GuidAttribute("20F1E61E-377A-471A-B705-ACF670637808"), ProgIdAttribute("EventHandlerAddin.Connect")> _
Public Class Connect
   Implements Extensibility.IDTExtensibility2

   Private m_objDTE As EnvDTE.DTE

   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

      m_objDTE = CType(application, EnvDTE.DTE)

      Select Case connectMode

         Case ext_ConnectMode.ext_cm_AfterStartup
         Case ext_ConnectMode.ext_cm_Startup
            ' OnStartupComplete method will be called automatically

      End Select

   End Sub

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

   End Sub

   Private Sub AddEventHandler()

      Dim objIDesignerHost As Design.IDesignerHost
      Dim objIComponentChangeService As IComponentChangeService
      Dim objIEventBindingService As IEventBindingService
      Dim objWindow As Window
      Dim objWindowObject As Object
      Dim objEventDescriptor As EventDescriptor
      Dim objComponent As IComponent
      Dim sEventName As String
      Dim sEventHandlerName As String
      Dim objPropertyDescriptor As PropertyDescriptor
      Dim objProjectItem As ProjectItem
      Dim objCodeElement As CodeElement
      Dim objEditPoint As EditPoint


         ' Get the active window
         objWindow = m_objDTE.ActiveWindow

         If Not (objWindow Is Nothing) Then

            ' Get the file
            objProjectItem = objWindow.ProjectItem

            ' Get the underlying object of the active window
            objWindowObject = objWindow.Object

            ' Check if it is a Windows Form
            If TypeOf objWindowObject Is IDesignerHost Then

               ' Get the designer host
               objIDesignerHost = DirectCast(objWindowObject, IDesignerHost)

               ' Get the services that are required
               objIComponentChangeService = DirectCast(objIDesignerHost.GetService( _
                  GetType(IComponentChangeService)), IComponentChangeService)
               objIEventBindingService = DirectCast(objIDesignerHost.GetService( _
                  GetType(IEventBindingService)), IEventBindingService)

               ' Get the component or control. In this case we use the root component, 
               ' that is, the form, but we could use
               ' any control in IDesignerHost.Container.Components
               objComponent = objIDesignerHost.RootComponent

               ' Initialize the name of the event that we want to use
               sEventName = "Load"

               ' Initialize the name of the event handler
               sEventHandlerName = objComponent.Site.Name & "_" & sEventName

               ' Get the event descriptor
               objEventDescriptor = TypeDescriptor.GetEvents(objComponent).Item(sEventName)

               ' Get the property descriptor for the event descriptor
               objPropertyDescriptor = objIEventBindingService.GetEventProperty(objEventDescriptor)

               ' If the event handler is not bound yet...
               If objPropertyDescriptor.GetValue(objComponent) Is Nothing Then

                  ' Bind the event handler to the event, notifying the change
                  objIComponentChangeService.OnComponentChanging(objComponent, objPropertyDescriptor)
                  objPropertyDescriptor.SetValue(objComponent, sEventHandlerName)
                  objIComponentChangeService.OnComponentChanged(objComponent, objPropertyDescriptor, _
                     Nothing, sEventHandlerName)

                  ' Show the code of the (empty) event handler

                  ' Get the code element of the event handler
                  objCodeElement = GetCodeElementByName(objProjectItem.FileCodeModel.CodeElements, sEventHandlerName)

                  ' Get the first line of the body and add some code
                  objEditPoint = objCodeElement.GetStartPoint(vsCMPart.vsCMPartBody).CreateEditPoint
                  objEditPoint.Insert("' Hello World")

               End If

            End If

         End If

      Catch objException As Exception
      End Try

   End Sub

   Private Function GetCodeElementByName(ByVal colCodeElements As CodeElements, _
      ByVal sName As String) As CodeElement

      Dim objCodeElement As CodeElement
      Dim objResult As CodeElement

      For Each objCodeElement In colCodeElements

         If objCodeElement.Name = sName Then
            objResult = objCodeElement
            Select Case objCodeElement.Kind
               Case vsCMElement.vsCMElementNamespace
                  objResult = GetCodeElementByName(DirectCast(objCodeElement, CodeNamespace).Members, sName)
               Case vsCMElement.vsCMElementClass
                  objResult = GetCodeElementByName(DirectCast(objCodeElement, CodeClass).Members, sName)
            End Select
         End If

         If Not (objResult Is Nothing) Then
            Exit For
         End If


      Return objResult

   End Function

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

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

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

End Class

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