Logo
HOWTO: Create a command with a custom picture using an ImageList for a XML-based Visual Studio add-in.

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

This article explains how to create a command with a custom picture in a XML-based add-in without using a satellite dll or a resource file in the own dll of the add-in, just passing the image from an ImageList in the EnvDTE80.Commands2.AddNamedCommand2 method. This approach only works in Visual Studio 2010 or higher, it doesn't work in Visual Studio 2005 or 2008.

More information

The Bitmap parameter of the EnvDTE80.Commands2.AddNamedCommand2 method is of System.Object type, and while originally it was intended for a numeric Id for the bitmap resource in the satellite resources dll, in Visual Studio 2010 Microsoft changed the internal implementation to accept a direct System.Drawing.Icon or System.Drawing.Bitmap.

The following sample shows the code of an add-in that creates a command with a custom picture from an ImageList and adds a button to the "Standard" commandbar of Visual Studio. The steps are the following:

  • Create an add-in using VB.NET/C# with the name "MyAddin".
  • Add a reference to System.Windows.Forms.
  • Add a form named "Form1" with a public ImageList control named "ImageList1", and load some 16x16 icon with 24-bit color depth (icons support transparency natively) to the ImageList control.
  • Use the following code in the Connect file:
Language: VB.NET   Copy Code Copy Code (IE only)
Imports System
Imports Microsoft.VisualStudio.CommandBars
Imports Extensibility
Imports EnvDTE
Imports EnvDTE80

Public Class Connect
    Implements Extensibility.IDTExtensibility2
    Implements IDTCommandTarget

    Private Const MY_COMMAND_NAME As String = "MyCommand"
    Private Const MY_COMMAND_CAPTION As String = "My command"
    Private Const MY_COMMAND_TOOLTIP As String = "My command tooltip"

    Private applicationObject As EnvDTE.DTE
    Private addInInstance As EnvDTE.AddIn
    Private frm1 As Form1

    Private myStandardCommandBarButton As CommandBarButton

    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

        Try

            applicationObject = CType(application, EnvDTE.DTE)
            addInInstance = CType(addInInst, EnvDTE.AddIn)

            Select Case connectMode

                Case ext_ConnectMode.ext_cm_UISetup

                    ' Do nothing for this add-in with temporary user interface

                Case ext_ConnectMode.ext_cm_Startup

                    ' The add-in was marked to load on startup
                    ' Do nothing at this point because the IDE may not be fully initialized
                    ' Visual Studio will call OnStartupComplete when fully initialized

                Case ext_ConnectMode.ext_cm_AfterStartup

                    ' The add-in was loaded by hand after startup using the Add-In Manager
                    ' Initialize it in the same way that when is loaded on startup
                    AddTemporaryUI()

            End Select

        Catch ex As System.Exception
            System.Windows.Forms.MessageBox.Show(ex.ToString)
        End Try

    End Sub

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

        AddTemporaryUI()

    End Sub

    Public Sub AddTemporaryUI()

        Const VS_STANDARD_COMMANDBAR_NAME As String = "Standard"

        Dim myCommand As Command = Nothing
        Dim standardCommandBar As CommandBar
        Dim commandBars As CommandBars
        Dim commands2 As EnvDTE80.Commands2

        Try

            frm1 = New Form1()

            commands2 = DirectCast(applicationObject.Commands, EnvDTE80.Commands2)

            ' Try to get the command if already exists
            Try
                myCommand = commands2.Item(addInInstance.ProgID & "." & MY_COMMAND_NAME)
            Catch
            End Try

            ' Add the command if it does not exist
            If myCommand Is Nothing Then

                myCommand = commands2.AddNamedCommand2(addInInstance, MY_COMMAND_NAME, _
                   MY_COMMAND_CAPTION, MY_COMMAND_TOOLTIP, False, frm1.ImageList1.Images.Item(0), Nothing, _
                   vsCommandStatus.vsCommandStatusSupported Or vsCommandStatus.vsCommandStatusEnabled)

            End If

            ' Get the "Standard" commmandbar
            commandBars = DirectCast(applicationObject.CommandBars, CommandBars)
            standardCommandBar = commandBars.Item(VS_STANDARD_COMMANDBAR_NAME)

            ' Add a button to the commandbar
            myStandardCommandBarButton = DirectCast(myCommand.AddControl(standardCommandBar, _
               standardCommandBar.Controls.Count + 1), CommandBarButton)

            ' Set the properties of the button
            myStandardCommandBarButton.Caption = MY_COMMAND_CAPTION
            myStandardCommandBarButton.Style = MsoButtonStyle.msoButtonIcon
            myStandardCommandBarButton.BeginGroup = True

        Catch ex As System.Exception
            System.Windows.Forms.MessageBox.Show(ex.ToString)
        End Try

    End Sub

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

        Try

            Select Case RemoveMode

                Case ext_DisconnectMode.ext_dm_HostShutdown, ext_DisconnectMode.ext_dm_UserClosed

                    If Not (myStandardCommandBarButton Is Nothing) Then
                        myStandardCommandBarButton.Delete()
                    End If

                    If Not frm1 Is Nothing Then
                        frm1.Dispose()
                    End If
            End Select

        Catch ex As System.Exception
            System.Windows.Forms.MessageBox.Show(ex.ToString)
        End Try

    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

    Public Sub Exec(ByVal cmdName As String, ByVal executeOption As vsCommandExecOption, _
       ByRef varIn As Object, ByRef varOut As Object, ByRef handled As Boolean) _
       Implements IDTCommandTarget.Exec

        handled = False

        If (executeOption = vsCommandExecOption.vsCommandExecOptionDoDefault) Then

            If cmdName = addInInstance.ProgID & "." & MY_COMMAND_NAME Then
                handled = True
                System.Windows.Forms.MessageBox.Show("Command executed.")
            End If

        End If

    End Sub

    Public Sub QueryStatus(ByVal cmdName As String, ByVal neededText As vsCommandStatusTextWanted, _
       ByRef statusOption As vsCommandStatus, ByRef commandText As Object) _
       Implements IDTCommandTarget.QueryStatus

        If neededText = vsCommandStatusTextWanted.vsCommandStatusTextWantedNone Then

            If cmdName = addInInstance.ProgID & "." & MY_COMMAND_NAME Then
                statusOption = CType(vsCommandStatus.vsCommandStatusEnabled + _
                   vsCommandStatus.vsCommandStatusSupported, vsCommandStatus)
            Else
                statusOption = vsCommandStatus.vsCommandStatusUnsupported
            End If

        End If

    End Sub

End Class
Language: C#   Copy Code Copy Code (IE only)
using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;
using System.Resources;
using System.Reflection;
using System.Globalization;
using System.Windows.Forms;

namespace MyAddin
{
   public class Connect : Extensibility.IDTExtensibility2, IDTCommandTarget
   {
      private const string MY_COMMAND_NAME = "MyCommand";
      private const string MY_COMMAND_CAPTION = "My command";
      private const string MY_COMMAND_TOOLTIP = "My command tooltip";

      private EnvDTE.DTE applicationObject;
      private EnvDTE.AddIn addInInstance;

      private CommandBarButton myStandardCommandBarButton;
      private Form1 frm1;

      public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode,
         object addInInst, ref System.Array custom)
      {
         try
         {
            applicationObject = (EnvDTE.DTE)application;
            addInInstance = (EnvDTE.AddIn)addInInst;

            switch (connectMode)
            {
               case ext_ConnectMode.ext_cm_UISetup:

                  // Do nothing for this add-in with temporary user interface
                  break;

               case ext_ConnectMode.ext_cm_Startup:

                  // The add-in was marked to load on startup
                  // Do nothing at this point because the IDE may not be fully initialized
                  // Visual Studio will call OnStartupComplete when fully initialized
                  break;

               case ext_ConnectMode.ext_cm_AfterStartup:

                  // The add-in was loaded by hand after startup using the Add-In Manager
                  // Initialize it in the same way that when is loaded on startup
                  AddTemporaryUI();
                  break;
            }
         }
         catch (System.Exception ex)
         {
            System.Windows.Forms.MessageBox.Show(ex.ToString());
         }
      }

      public void OnStartupComplete(ref System.Array custom)
      {
         AddTemporaryUI();
      }

      public void AddTemporaryUI()
      {
         const string VS_STANDARD_COMMANDBAR_NAME = "Standard";

         Command myCommand = null;
         CommandBar standardCommandBar = null;
         CommandBars commandBars = null;
         EnvDTE80.Commands2 commands2;
         object[] contextUIGuids = new object[] { };

         try
         {

            frm1 = new Form1();

            commands2 = (EnvDTE80.Commands2)applicationObject.Commands;

            // Try to get the command if already exists 
            try
            {
               myCommand = commands2.Item(addInInstance.ProgID + "." + MY_COMMAND_NAME, -1);
            }
            catch
            {
            }

            // Add the command if it does not exist
            if (myCommand == null)
            {
               myCommand = commands2.AddNamedCommand2(addInInstance,
                  MY_COMMAND_NAME, MY_COMMAND_CAPTION, MY_COMMAND_TOOLTIP, false, frm1.imageList1.Images[0], ref contextUIGuids,
                  (int)(vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled));
            }

            // Get the "Standard" commandbar
            commandBars = (CommandBars)applicationObject.CommandBars;
            standardCommandBar = commandBars[VS_STANDARD_COMMANDBAR_NAME];

            // Add a button to the commandbar
            myStandardCommandBarButton = (CommandBarButton)myCommand.AddControl(standardCommandBar,
               standardCommandBar.Controls.Count + 1);

            // Set the properties of the button
            myStandardCommandBarButton.Caption = MY_COMMAND_CAPTION;
            myStandardCommandBarButton.Style = MsoButtonStyle.msoButtonIcon;
            myStandardCommandBarButton.BeginGroup = true;
         }
         catch (System.Exception ex)
         {
            System.Windows.Forms.MessageBox.Show(ex.ToString());
         }
      }

      public void OnDisconnection(Extensibility.ext_DisconnectMode RemoveMode, ref System.Array custom)
      {
         try
         {
            switch (RemoveMode)
            {
               case ext_DisconnectMode.ext_dm_HostShutdown:
               case ext_DisconnectMode.ext_dm_UserClosed:

                  if ((myStandardCommandBarButton != null))
                  {
                     myStandardCommandBarButton.Delete(true);
                  }

                  if (frm1 != null)
                  {
                     frm1.Dispose();
                  }
                  
                  break;
            }
         }
         catch (System.Exception ex)
         {
            System.Windows.Forms.MessageBox.Show(ex.ToString());
         }
      }

      public void OnBeginShutdown(ref System.Array custom)
      {
      }

      public void OnAddInsUpdate(ref System.Array custom)
      {
      }

      public void Exec(string cmdName, vsCommandExecOption executeOption, ref object varIn,
         ref object varOut, ref bool handled)
      {

         handled = false;

         if ((executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault))
         {
            if (cmdName == addInInstance.ProgID + "." + MY_COMMAND_NAME)
            {
               handled = true;
               System.Windows.Forms.MessageBox.Show("Command executed.");
            }
         }
      }

      public void QueryStatus(string cmdName, vsCommandStatusTextWanted neededText,
         ref vsCommandStatus statusOption, ref object commandText)
      {
         if (neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
         {
            if (cmdName == addInInstance.ProgID + "." + MY_COMMAND_NAME)
            {
               statusOption = (vsCommandStatus)(vsCommandStatus.vsCommandStatusEnabled |
                  vsCommandStatus.vsCommandStatusSupported);
            }
            else
            {
               statusOption = vsCommandStatus.vsCommandStatusUnsupported;
            }
         }
      }

   }
}

Related articles



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


Top