The Command User Interface


Visual Studio borrows its toolbar and menu system from the Microsoft Office suite of applications. The command bars provide a common user interface experience across all of the Office applications as well as Visual Studio. Because the command bars also support an object model, these applications also share a common programming model for accessing the command bar structure.

The main point of access to the command bar objects is through the DTE.CommandBars property. This property returns a System.Object type, which can be converted into a Microsoft. VisualStudio.CommandBars.CommandBars object, which is defined in the assembly Microsoft. VisualStudio.CommandBars.dll. The following macro code demonstrates retrieving this object:

 Sub GetCommandBars()     Dim commandBars As Microsoft.VisualStudio.CommandBars.CommandBars     commandBars = DTE.CommandBars End Sub 

The Command Bar Object Model

The command bar object model is arranged in a treelike hierarchy, in the same way as the Visual Studio object model. At the top of this tree is a collection of Microsoft.VisualStudio. CommandBars.CommandBar objects that includes all the command bars, shortcut menus, and the main menu bar. Each command bar contains a collection of controls that have the type Microsoft.VisualStudio.CommandBars.CommandBarControl. Once a CommandBarControl is retrieved, it can be converted into one of a number of different types. One type, a CommandBarButton, is any menu item on a command bar that the user can click to perform an action; this is analogous to executing a Visual Studio command. To get to a CommandBarButton object, a cast must be performed from the CommandBarControl object:

 Sub GetCommandBarButton()     Dim commandBarBtn As Microsoft.VisualStudio.CommandBars.CommandBarButton     Dim commandBarCtl As Microsoft.VisualStudio.CommandBars.CommandBarControl     Dim commandBarCtls As Microsoft.VisualStudio.CommandBars.CommandBarControls     'Find the View command bar     commandBarCtls = DTE.CommandBars.Item("View").Controls     'Retrieve the first control on the menu      commandBarCtl = commandBarCtls.Item(1)     'Convert the CommandBarControl to a CommandBarButton object      commandBarBtn = CType(commandBarCtl, _         Microsoft.VisualStudio.CommandBars.CommandBarButton)     MsgBox(commandBarBtn.Caption) End Sub 

The object returned from the Controls collection can be converted into a CommandBarPopup if the item is the root node of a submenu. An example of this is the New item on the File menu; when the user holds the mouse cursor over this menu, a submenu appears. You can also retrieve a CommandBarPopup when the item is on a split-button drop-down menu, such as the New Project | New Blank Solution button on the Standard command bar:

 Sub GetCommandBarPopup()     Dim commandBar As Microsoft.VisualStudio.CommandBars.CommandBar     Dim cmdBarControl As Microsoft.VisualStudio.CommandBars.CommandBarControl     Dim cmdBarPopup As Microsoft.VisualStudio.CommandBars.CommandBarPopup     'Find the "Standard" command bar     commandBar = DTE.CommandBars.Item("Standard")     'Find the first control on the command bar     cmdBarControl = commandBar.Controls.Item(1)     'Convert the CommandBarControl to a CommandBarPopup     cmdBarPopup = CType(cmdBarControl, _         Microsoft.VisualStudio.CommandBars.CommandBarPopup)     MsgBox(cmdBarPopup.Controls.Item(1).Caption) End Sub 

A popup menu is itself a command bar. You can't cast directly to a CommandBar object on a popup menu, but this object does contain a CommandBar property, which returns a CommandBar object, which itself has a collection of controls (as you can see in the next-to-last line in the preceding macro code).

The Primary Command Bar

The DTE.CommandBars property returns the collection of all CommandBar objects available within Visual Studio, but the most commonly used command bar is the main menu. Looking at the menu, you can see the File, Edit, and View items as well as a number of additional menu items; all of these are CommandBar objects within the DTE.CommandBars collection. But because there might be multiple items within the collection with the same name, indexing the collection by using the name might not work. For example, there are multiple CommandBar objects with the title View, and you might not always get the one you want if you index the CommandBars collection with the string View. The following macro might return the View command bar for the SQL editor, a deployment project popup menu, or the View menu:

 Sub GetView()     Dim cmdbars As Microsoft.VisualStudio.CommandBars.CommandBars     Dim commandBar As Microsoft.VisualStudio.CommandBars.CommandBar     cmdbars = DTE.CommandBars     commandBar = cmdbars.Item("View") End Sub 

To work around this, you can find the CommandBar object for the menu bar, called MenuBar, and then find the View submenu command bar:

 Sub GetMenuCommandBar()      Dim commandBar As Microsoft.VisualStudio.CommandBars.CommandBar      Dim cmdBarControl As Microsoft.VisualStudio.CommandBars.CommandBarControl      Dim cmdBarPopupView As Microsoft.VisualStudio.CommandBars.CommandBarPopup      Dim cmdBarView As Microsoft.VisualStudio.CommandBars.CommandBar     'Retrieve the MenuBar command bar      commandBar = DTE.CommandBars.Item("MenuBar")     'Find the View menu     cmdBarControl = commandBar.Controls.Item("View")     'Convert to a CommandBarPopup     cmdBarPopupView = CType(cmdBarControl, _         Microsoft.VisualStudio.CommandBars.CommandBarPopup)      'Get the CommandBar object for the view menu     cmdBarView = cmdBarPopupView.CommandBar     MsgBox(cmdBarView.Name) End Sub 

By default, if the Add-in Wizard generates an add-in and the option is selected to place an item on the Tools menu, code is generated to place a menu item on the Tools menu of the menu bar. If you want to move this command user interface to a different menu, you can simply change the string Tools to a different menu title, but be careful to select the correct menu. It's easy to make the mistake of selecting the wrong command bar, causing the command button to seemingly disappear because it was placed somewhere that you did not expect it to go.

Adding New Command Bar Elements

With a Command object in hand (found by either indexing the Commands collection or adding a new command), and after using the methods described earlier to find the proper command bar, you can add new UI elements to that command bar that invokes your command when clicked. You do this by using the Command.AddControl method. When a control is added, the control type of the command (either passed to the call of AddNamedCommand2 or the type of one of the built-in commands) is used to create the appropriate command type, be that a menu item, an MRU menu item list, or one of the two combo box types. When commands are created, they are persisted to disk and re-created automatically the next time Visual Studio is started. Likewise, when you place a control on a command bar by using the AddControl method, that control and its placement are saved to disk and re-created when Visual Studio is run. The first argument of the AddControl method is the CommandBar object that the button is to be placed on. The second argument defines the numerical position of the control in relation to the other controls on the command bar. (If this value is 1, the control will be the first item on the command bar, and if the value is 2, it will be the second item, and so forth.)

You can hard-code an index to place the control, but the control might not appear where you think it should go in relation to other controls. The reason is that a command bar might have one or more separators (or lines drawn between two controls) that divide controls into logical groups. These groups are also controls on the command bar, and they should be counted when you calculate the position. Not only are group controls counted as items in the index, but so are controls that are not visible because the value vsCommandStatusInvisible is returned from your QueryStatus method. If the control to be added should be placed at the bottom or end of the command bar, you can use the Controls.Count property to determine the final position:

 Sub AddControl()     Dim command As EnvDTE.Command     Dim commandBar As Microsoft.VisualStudio.CommandBars.CommandBar     'Find the File.OpenFile command     command = DTE.Commands.Item("File.OpenFile")     'Find the Tools CommandBar     commandBar = DTE.CommandBars.Item("Tools")     'Add a control to the Tools menu that when     ' clicked will invoke the File.OpenFile command     command.AddControl(commandBar, commandBar.Controls.Count + 1)   End Sub 

Note that the index used doesn't fix a control to a particular position. If you add a control to position 1 and a second control is added to position 1, the first control is pushed into the second position.

At times, it might make sense to create a new command bar to place your buttons on because the default set of command bars doesn't suit your needs. The command bar object model allows you to create new command bars, but creating one in this way might not achieve the desired effects. Command bars created in this way are created in a temporary state, which means that when you exit and restart Visual Studio, the command bar will have been destroyed. Because the button user interface for commands persists across instances, you'll want your command bars to also persist across instances. The Visual Studio object model lets you do this by using the Commands.AddCommandBar method, which has this signature:

 object AddCommandBar(string Name, EnvDTE.vsCommandBarType Type, _   Microsoft.VisualStudio.CommandBars.CommandBar   CommandBarParent = null, int Position = 1) 

This method has the following arguments:

  • Name The caption to display on the command bar.

  • Type A value from the vsCommandBarType enumeration. If the value is vsCommandBarTypeToolbar, a command bar is created that can be docked to the top, left, bottom, or right of the Visual Studio window. If the value is vsCommandBarTypeMenu, the command bar is added as a submenu to another command bar. If the value is vsCommandBarTypePopup, a shortcut menu is created.

  • CommandBarParent If the value passed for the Type parameter is vsCommandBarTypeToolbar or vsCommandBarTypePopup, this value should be null or Nothing (depending on the language used). If the value passed to the Type parameter is vsCommandBarTypeMenu, the new menu should be rooted on the command bar object.

  • Position This value is necessary only if the Type parameter is set to vsCommandBarTypeMenu. It defines the location on the parent command bar where the new menu command is placed. It has the same meaning as the Position parameter of the AddControl method.

How the newly created command bar is shown to the user depends on the type of command bar that's created. If the command bar type is a new menu, the menu item is hidden from the user until the command bar for that menu item is populated with buttons. If the command bar created is a new toolbar, the Visible property of the returned CommandBar object should be set to True. If a popup menu is created, you can show the menu to the user by using the CommandBar.ShowPopup method, which takes two arguments, the x and y coordinates of the top left of where the popup menu should appear.

Using Custom Bitmaps

Visual Studio has a number of predefined bitmaps that you can place on menu items and command bar buttons, but they might not always meet your needs. To use your own bitmap for the image on a button, you must create for your add-in a satellite DLL that contains the bitmap as a resource, and then change the call to Commands2.AddNamedCommand2 so Visual Studio can find your bitmap. First, you should set the AddNamedCommand2 method's MSOButton parameter to false to tell Visual Studio that the bitmap isn't among the default, built-in pictures but is in the satellite DLL. Second, you should change the Bitmap parameter to the resource name of the bitmap in your satellite DLL; however, unlike other places where resource names can use alphanumeric values for the resource names, this method accepts only a number in the form of a string for the resource name. The bitmap must be in a specific format to be usable by Visual Studio. It must be 16 pixels high and 16 pixels wide, and it must be saved so that it has either 4-bit color (16 colors) or 32-bit color (4,294,967,296 colors). Visual Studio can also draw the picture so that a portion of it shows as transparent, causing the command bar background to bleed through. To enable this, you must make the transparent area have the RGB (red, green, blue) color value of 0, 254, 0. Note that this color isn't the lime green color displayed in the color palette of the Visual Studio image editor or the Windows Paint application, and you will need to use the palette color manipulation features built into those tools.

Once you have created the .resx file and the bitmap within that file, you then need to generate the satellite DLL. I like to use the command line console rather than Visual Studio to generate the DLL. This is purely a matter of personal preference; you can use Visual Studio to build it for you. Using the integrated resource editor makes editing the .resx file much easier.

The sample CommandTypes, which was used earlier to demonstrate creating commands that implement combo-boxes and MRU menu item lists, also uses a custom bitmap with transparency for some of the command menu items. The call to AddNamedCommand2 has been modified as described earlier; all that is left is to generate the satellite DLL. In the Localization folder, along with the CommandTypes sample is a batch file, MakeSatelliteDLL. bat, which will generate the satellite DLLs. This batch file repeats the following bit of code many times, but for a selection of different languages:

 Resgen CommandTypes.en-US.resx Al.exe /t:lib /embed:CommandTypes.en-US.resources   /culture:en-US /out:CommandTypes.resources.dll md .\..\CommandTypes\bin\en-US copy CommandTypes.resources.dll .\..\CommandTypes\bin\en-US 

The first line of this code takes a resource file, in this case the resources for the U.S. English culture, and creates a .resources file with the name CommandTypes-en-US.resources. Next, the assembly linker tool (Al.exe) is called to build a library DLL with the U.S. English resources embedded within it, and it names that file CommandTypes.resources.dll. The final two lines simply copy the file into a folder named en-US that is located in the same directory as the add-in DLL. When you call AddNamedCommand2 from your add-in and the MSOButton parameter is set to false, Visual Studio will search for the satellite DLL assembly, load it, find the specified bitmap resource, and then apply it for the command UI that is created for that command. You do not need to modify the .addin file to specify the satellite DLL; Visual Studio will find it by using the .NET Framework's System.Reflection.Assembly. GetSatelliteAssembly method.




Working with Microsoft Visual Studio 2005
Working with Microsoft Visual Studio 2005
ISBN: 0735623155
EAN: 2147483647
Year: 2006
Pages: 100

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net