The
Commands are the most fundamental mechanism of communication between the
If you've written user interface software for the Microsoft Windows operating system, you're probably familiar with the event-driven programming model. When the user clicks a button on a form, chooses a menu item, or presses a key on the keyboard, your program receives a notification of that user action. If you're programming at the Windows SDK level, such as with the Microsoft Visual C++ programming language, when the user
Visual Studio uses a method of notification similar to that of Win32
A command also needs another part to identify itself. After all, if every command had just a GUID to identify it, and all the commands that belonged to an add-on had the same GUID, an add-on wouldn't be able to tell the difference between, for instance, the New File command and the New Project command. To disambiguate commands that all have the same GUID, a number, or ID, is assigned to each command in that
| Note |
A command in Visual Studio exists independently of any user interface elements (such as menu items) for that command. Commands can be created and
|
In Visual Studio, all the commands that a user can issue are represented in the object model by a Command object, and the Commands collection contains a list of these objects. As do other collection objects, Command objects allow the use of standard enumeration constructs such as the keywords foreach in Visual C# or For Each in Visual Basic. Using these keywords, we can create a macro to walk the list of all Command objects:
Sub WalkCommands() Dim cmd As EnvDTE.Command For Each cmd In DTE.Commands 'use the EnvDTE.Command object here Next End Sub
The
Command
collection's
Item
method works a bit differently from the
Item
Sub FindFileOpenCommand() Dim cmd As EnvDTE.Command cmd = DTE.Commands.Item("{}", 222) End Sub
As you can see, code like this can be complicated to write because you need to find and learn the GUID and ID for every command (which would be hard to do because there can be thousands of them), and then you must type this pair correctly every time, which can be a source of programming errors. To help with finding a
Command
object, the
Commands.Item
method accepts another format for indexing the collection, which is easier to remember: the
Remembering the GUID and ID for every command can be a huge waste of brainpower, so Visual Studio defines an easier-to-remember textual representation for most commands. These names follow a general pattern: the text of the top-level menu on which the primary user interface element for the command is located followed by a period, the text of all submenus combined followed by a period, and finally the text of the menu item. Any non-
Sub FindFileOpenCommandByName() Dim command As EnvDTE.Command command = DTE.Commands.Item("File.OpenFile") End Sub
To find the GUID and ID pair of a command, you can use the GUID and ID properties of the Command object. We used these two properties to find the GUID and ID pair used in the FindFileOpenCommand macro shown earlier. This is the macro we used to find them:
Sub FindGuidIDPair() Dim guid As String Dim id As Integer Dim command As EnvDTE.Command command = DTE.Commands.Item("File.OpenFile") guid = command.Guid id = command.ID MsgBox(guid + ", " + id.ToString()) End Sub
You can see the entire list of all available commands from within the Options dialog box on the Environment Keyboard page. You can also use the object model to find available command names. We'll do this with the EnvDTE.Commands collection in this example macro:
Sub CreateCommandList() Dim command As EnvDTE.Command Dim output As New OutputWindowPaneEx(DTE, "Create Command List") For Each command In DTE.Commands If (command.Name <> Nothing) Then output.WriteLine(command.Name) End If Next End Sub
When the macro is run, it places into the Output window the name of each command. If you examine the macro closely enough, you'll notice a special check to verify that the name of the command isn't set to
Nothing
. This check is done because if a command doesn't have a name set, it returns
Nothing
if it's using Visual Basic or
null
if it's using C#. Commands that don't have a name are usually used internally by Visual Studio for private communication, and the user
The purpose of a command is to provide a way for the user to direct Visual Studio to perform some action. Commands can be invoked in a number of ways, the most common of which is for the user to choose a menu item or click a toolbar button. But commands can also be run in other ways. For example, if you write a macro that conforms to the standard macro notation (it is defined as public, doesn't return a value, and takes no arguments unless the arguments are optional strings), the macros facility detects that macro and creates a command for it. Double-clicking that macro in the Macro Explorer window executes the command associated with that macro, which is handled by the Macros editor. A third way to run a command is to use the
DTE.ExecuteCommand
method. This method runs a command, given by name, as if the user had
To run our File.OpenFile command by using the ExecuteCommand method, we would write code like this:
Sub RunFileOpenCommand() DTE.ExecuteCommand("File.OpenFile") End Sub
When a call is made to the ExecuteCommand method, execution of the macro or add-in waits until the command finishes executing.
A final approach, which is useful for the power user, is to type the name of the command into the Command Window. The Command Window is a text-based window in which you type the names of commands; when the user presses the Enter key, the command is run.
The command name that you type into the Command Window is the same name that is returned from the Command.Name property, and it can be passed to the ExecuteCommand method.
As mentioned before, macros that follow a special format are automatically turned into commands, and these macro commands are given a named
Sub RunCommand() DTE.ExecuteCommand("Macros.Samples.Utilities.TurnOnLineNumbers") End Sub