Logo
PRB: Performance problem of DTE.CommandBars[name] for CommandbarPopups in Visual Studio 2010

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio 2010
Date: May 2011    
       
Introduction

This article discusses a performance problem that happens when an add-in for Visual Studio 2010 tries to get a CommandbarPopup by name using DTE.CommandBars[name] such as DTE.CommandBars["Tools"] to retrieve the "Tools" commandbar of the menu bar. This problem did not happen in Visual Studio 2008.

More Information

Visual Studio provides several kinds of commandbars: menu bars (such as the main menu of Visual Studio), toolbars (such as the "Standard" toolbar, context menus (such as the context menu of the code window) and commandbar popups (commandbars inside other commandbar, such as the "Tools" menu on the main menu of Visual Studio). Commandbar popups are special: a Commandbar contains controls (CommandBar.Controls collection) and each control is of the type CommandBarControl, which can be a button (CommandBarButton type), or a commandbar popup (CommandBarPopup type). The CommandBarPopup type has the CommandBar property to get its commandbar.

The automation model of Visual Studio (EnvDTE) provides the EnvDTE.DTE.CommandBars collection, which you can use to get the menu bar, toolbar or a context menu knowing its name (see the article HOWTO: Guessing the name of a command bar to add a custom menu entry in Visual Studio .NET add-ins). However, the DTE.CommandBars collection should not be used to get a CommandBarPopup for the following reasons:

  • Commandbar names are not guaranteed to be unique. For example, there is more than one "View" commandbar name in the DTE.CommandBars collection. See the article HOWTO: Getting the 'View' command bar of Visual Studio .NET from an add-in.
  • Even if you want to use that approach for commandbar names that are likely to be unique, Visual Studio 2010 uses a new internal implementation of commandbars (WPF-based instead of Office-based) that has a performance problem accessing programmatically a commandbar popup in the DTE.CommandBars collection that hasn't been shown yet in the Visual Studio user interface.

There are two correct ways to locate a commandbar popup:

The following add-in provides the code to reproduce the performance problem of Visual Studio 2010 locating the "Tools" commandbar popup in the DTE.CommandBars collection. You will notice that it takes several seconds:

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

public class MyAddIn : Extensibility.IDTExtensibility2
{
   private EnvDTE.DTE applicationObject;

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

         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 e)
      {
         System.Windows.Forms.MessageBox.Show(e.ToString());
      }
   }

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

   public void AddTemporaryUI()
   {
      CommandBar toolsCommandBar = null;
      CommandBars commandBars = null;
      System.DateTime t1, t2;

      try
      {
         commandBars = (CommandBars)applicationObject.CommandBars;

         t1 = System.DateTime.Now;
         toolsCommandBar = commandBars["Tools"];
         t2 = System.DateTime.Now;

         MessageBox.Show(t2.Subtract(t1).TotalMilliseconds.ToString() + " milliseconds");
      }
      catch (System.Exception e)
      {
         System.Windows.Forms.MessageBox.Show(e.ToString());
      }
   }

   public void OnDisconnection(Extensibility.ext_DisconnectMode RemoveMode, ref System.Array custom)
   {
   }

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

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

}
Language: VB.NET   Copy Code Copy Code (IE only)
Imports System
Imports Microsoft.VisualStudio.CommandBars
Imports Extensibility
Imports EnvDTE
Imports EnvDTE80
Imports System.Windows.Forms

Public Class Connect
   Implements Extensibility.IDTExtensibility2

   Private applicationObject 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

      Try

         applicationObject = CType(application, EnvDTE.DTE)
   
         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 e As System.Exception
         System.Windows.Forms.MessageBox.Show(e.ToString)
      End Try

   End Sub

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

      AddTemporaryUI()

   End Sub

   Public Sub AddTemporaryUI()

      Dim toolsCommandBar As CommandBar
      Dim commandBars As CommandBars
      Dim t1, t2 As Date

      Try

         commandBars = DirectCast(applicationObject.CommandBars, CommandBars)

         t1 = Date.Now
         toolsCommandBar = commandBars.Item("Tools")
         t2 = Date.Now

         MessageBox.Show(t2.Subtract(t1).TotalMilliseconds & " milliseconds")

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

   End Sub

   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

Related articles


Go back to the 'Resources for Visual Studio .NET extensibility' section for more articles like this


Top