Logo
HOWTO: Manipulating controls of Windows forms from Visual Studio .NET add-ins

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

This article describes how to manipulate a Windows form and its controls (either selected or not) from a Visual Studio .NET add-in.

More Information

The following VB.NET sample shows you how to enumerate and manipulate the controls of a Windows Form or Usercontrol. When loaded, the add-in gets the active designer window, shows the count of selected controls (using the ISelectionService interface) and changes the Tag property of each control of the form.

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

   ' Note: 
   ' - Add the following references to the project:
   ' System.Windows.Forms

   ' - Add the following Imports to this file:
   ' Imports System.ComponentModel
   ' Imports System.ComponentModel.Design
   ' Imports System.Windows.Forms

   Dim objWindow As Window
   Dim objIDesignerHost As IDesignerHost
   Dim objIComponent As IComponent
   Dim colPropertyDescriptorCollection As PropertyDescriptorCollection
   Dim objPropertyDescriptor As PropertyDescriptor
   Dim objIContainer As IContainer
   Dim objIServiceProvider As IServiceProvider
   Dim objISelectionService As ISelectionService

   Try

      m_objDTE = DirectCast(application, EnvDTE.DTE)

      If connectMode = ext_ConnectMode.ext_cm_AfterStartup Then

         ' Get the active window
         ' Note: ensure that a Design window is active before running this code
         ' Note also that there is a bug in Visual Studio .NET
 and the ActiveWindow property 
         ' returns the first window of the document that was open, which could be
         ' the code window, and not the active window as it would be expected.

         objWindow = m_objDTE.ActiveDocument.ActiveWindow

         ' Get the designer host
         objIDesignerHost = DirectCast(objWindow.Object, IDesignerHost)

         ' Get the service provider
         objIServiceProvider = DirectCast(objIDesignerHost, IServiceProvider)

         ' Get the selection service
         objISelectionService = DirectCast(objIServiceProvider.GetService( _
            GetType(ISelectionService)), ISelectionService)

         ' Show the count of selected controls
         MessageBox.Show("The active designer has " & _
            objISelectionService.SelectionCount.ToString() & " control(s) selected.")

         ' Get the container
         objIContainer = objIDesignerHost.Container

         ' Iterate the components in a linear way (not hierarchically)
         For Each objIComponent In objIContainer.Components

            If TypeOf objIComponent Is Form Then

               ' This component is the form itself. You could cast it to a Form object
               ' and use its Controls collection to iterate the controls in a hierarchical way
               ' Skip it for the purpose of this sample.

            ElseIf TypeOf objIComponent Is UserControl Then

               ' Same previous comment, for the case of UserControls

            Else ' It is a control of the form, or a component of the component tray

               colPropertyDescriptorCollection = TypeDescriptor.GetProperties(objIComponent)

               objPropertyDescriptor = colPropertyDescriptorCollection.Item("Tag")

               If Not (objPropertyDescriptor Is Nothing) Then
                  objPropertyDescriptor.SetValue(objIComponent, "Tag modified")
               End If

            End If

         Next

      End If

   Catch objException As Exception

      MessageBox.Show(objException.ToString)

   End Try

End Sub

Remarks

  • This technique only works with Windows forms or usercontrols, not for Web forms or usercontrols.
  • There are other services that can be retrieved using the IServiceProvider. For example, the IEventBindingService, used to set or get the event handlers of controls.
  • In order to persist the changes of a property value, you should use a PropertyDescriptor as shown in the code instead of casting the component to the specific control and manipulating its properties directly.
  • There are 3 kind of items that can be returned by the Components collection of the container: components of the component tray of the form (for example, an ImageList control, which is not part of the form), the form and the controls of the form.
  • The Components collection of the container returns all the components and controls in a linear fashion. If you want to get them in a hierarchical fashion, you should get first the root component (IDesignerHost.RootComponent), cast it to a Windows Form or UserControl, and then use its Controls collection recursively.


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