This article explains how to add programmatically (from an add-in) an event
handler to a Windows Forms control.
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
OnStartupComplete(Nothing)
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
AddEventHandler()
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
Try
' 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
objIEventBindingService.ShowCode()
' 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
System.Windows.Forms.MessageBox.Show(objException.ToString)
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
Else
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
Next
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