Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
A language service can control what context menus are shown in the editor, by intercepting the SHOWCONTEXTMENU enumeration. Alternately, you can control the context menu on a per-marker basis. For more information see Important Commands for Language Service Filters.
Note
Beginning with Visual Studio 2008 SDK, use XML Command Table (.vsct) files instead of command table configuration (.ctc) files to define how menus and commands appear in your VSPackages. For more information, see Visual Studio Command Table (.Vsct) Files
Adding Commands to the Editor Context Menu
To add a command to the context menu, you must first define a set of menu commands in a .ctc-file belonging to a specific group. These commands must be invisible and disabled by default. The following code is from the ctc-file generated as a part of the walkthrough, Walkthrough: Adding a Command to an Editor Generated by the Package Wizard:
NEWGROUPS_BEGIN
// NewGroup Parent Group Priority
guidTestEditorCmdSet:MyMenuGroup,
guidSHLMainMenu:IDM_VS_MENU_EDIT,
0x0600;
NEWGROUPS_END
BUTTONS_BEGIN
// Command Parent Group Priority Image Type Visibility
guidTestEditorCmdSet:cmdidColorFont,
guidTestEditorCmdSet:MyMenuGroup,
0x0100,
guidTestEditorCmdSet:bmpPicSmile,
BUTTON,
DYNAMICVISIBILITY | DEFAULTINVISIBLE | DEFAULTDISABLED,
"Color Text";
guidTestEditorCmdSet:cmdidMyCommand,
guidSHLMainMenu:IDM_VS_MENU_TOOLS,
0x0100,
guidTestEditorCmdSet:bmpPic1,
BUTTON, ,
"My Command Name";
The above ctc-file code adds two menu buttons, one to the Edit menu and one to the Tools menu. The command Color Text is added to the Edit menu and the command My Command Name is added to the Tools menu.
The Parent Group setting determines the primary group the command belongs to. Every menu button must belong to a primary parent group.
The Image setting adds an optional icon that appears next to the menu button in the menu. For example, the Color TextImage parameter is set to guidTestEditorCmdSet:bmpPic1 to include a smiley-face icon. The bmpPic1 is a bitmap provided by the template generated by the Visual Studio Integration Package wizard.
The Priority setting determines the order in which the command buttons appear in the given menu where a smaller number indicates a higher priority.
The Color Text menu button has its Visibility set to DYNAMICVISIBILITY | DEFAULTINVISIBLE | DEFAULTDISABLED. This sets the visibility to be invisible and disabled by default. In practice this means that the menu item is grayed out and inaccessible in the Edit menu until it is activated. In the Walkthrough: Adding a Command to an Editor Generated by the Package Wizard walkthrough, the Color Text menu button is programmed to be dynamically visible if a portion of text in the editor pane is selected.
You can also use predefined commands that do not need to be defined in the ctc-file. For example, if you examine the EditorPane.cs file generated by the Visual Studio Integration Package wizard, you find that a set of predefined commands, such as SelectAll defined by GUID_VSStandardCommandSet97, are handled in the QueryStatus and Exec methods without ctc-file entries. For more information on the Visual Studio Integration Package wizard, see How to: Create VSPackages (C# and Visual Basic).
Executing the Commands
Executing the commands is a two step process, detailed below:
Implement the QueryStatus method for the object that is monitoring your commands. The Visual Studio IDE calls the QueryStatus method to determine if a menu item should be visible and if it should be enabled or disabled. The following code sample is taken from the Walkthrough: Adding a Command to an Editor Generated by the Package Wizard walkthrough and shows the implementation for the commands generated by the Visual Studio Integration Package wizard, and the Color Text command added in the walkthrough:
Public Function QueryStatus(ByRef guidCmdGroup As Guid, ByVal cCmds As UInteger, ByVal prgCmds As OLECMD(), ByVal pCmdText As System.IntPtr) As Integer Debug.Assert(cCmds = 1, "Multiple commands") Debug.Assert(Not prgCmds Is Nothing, "NULL argument") If (prgCmds Is Nothing) Then Return VSConstants.E_INVALIDARG End If Dim cmdf As OLECMDF = OLECMDF.OLECMDF_SUPPORTED If guidCmdGroup = VSConstants.GUID_VSStandardCommandSet97 Then ' Process standard Commands. Select Case prgCmds(0).cmdID Case CUInt(VSStd97CmdID.SelectAll) ' Command is always enabled. cmdf = OLECMDF.OLECMDF_SUPPORTED Or OLECMDF.OLECMDF_ENABLED Exit Select Case CUInt(VSStd97CmdID.Copy), CUInt(VSStd97CmdID.Cut) ' Enable command if something is selected. If textBox1.SelectionLength > 0 Then cmdf = cmdf Or OLECMDF.OLECMDF_ENABLED End If Exit Select Case CUInt(VSStd97CmdID.Paste) ' Enable if clipboard has content that we can paste. If textBox1.CanPaste(DataFormats.GetFormat(DataFormats.Text)) Then cmdf = cmdf Or OLECMDF.OLECMDF_ENABLED End If Exit Select Case CUInt(VSStd97CmdID.Redo) If textBox1.CanRedo Then cmdf = cmdf Or OLECMDF.OLECMDF_ENABLED End If Exit Select Case CUInt(VSStd97CmdID.Undo) If textBox1.CanUndo Then cmdf = cmdf Or OLECMDF.OLECMDF_ENABLED End If Exit Select Case Else Return CInt(Fix(Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED)) End Select ElseIf guidCmdGroup = GuidList.guidTestEditorCmdSet Then ' Process our Commands Select Case prgCmds(0).cmdID Case PkgCmdIDList.cmdidColorFont ' Enable if something is selected. If textBox1.SelectionLength > 0 Then cmdf = cmdf Or OLECMDF.OLECMDF_ENABLED End If Exit Select Case Else Return CInt(Fix(Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED)) End Select Else Return CInt(Fix(Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED)) End If
public int QueryStatus(ref Guid guidCmdGroup, uint cCmds, OLECMD[] prgCmds, System.IntPtr pCmdText) { Debug.Assert(cCmds == 1, "Multiple commands"); Debug.Assert(prgCmds!=null, "NULL argument"); if ((prgCmds == null)) return VSConstants.E_INVALIDARG; OLECMDF cmdf = OLECMDF.OLECMDF_SUPPORTED; if (guidCmdGroup == VSConstants.GUID_VSStandardCommandSet97) { // Process standard Commands. switch (prgCmds[0].cmdID) { case (uint)VSStd97CmdID.SelectAll: { // Command is always enabled. cmdf = OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED; break; } case (uint)VSStd97CmdID.Copy: case (uint)VSStd97CmdID.Cut: { // Enable command if something is selected. if (textBox1.SelectionLength > 0) cmdf |= OLECMDF.OLECMDF_ENABLED; break; } case (uint)VSStd97CmdID.Paste: { // Enable if clipboard has content that we can paste. if (textBox1.CanPaste(DataFormats. GetFormat(DataFormats.Text))) cmdf |= OLECMDF.OLECMDF_ENABLED; break; } case (uint)VSStd97CmdID.Redo: { if (textBox1.CanRedo) cmdf |= OLECMDF.OLECMDF_ENABLED; break; } case (uint)VSStd97CmdID.Undo: { if (textBox1.CanUndo) cmdf |= OLECMDF.OLECMDF_ENABLED; break; } default: return (int)(Microsoft.VisualStudio.OLE. Interop.Constants.OLECMDERR_E_NOTSUPPORTED); } else if (guidCmdGroup == GuidList.guidTestEditorCmdSet) { // Process our Commands switch (prgCmds[0].cmdID) { case PkgCmdIDList.cmdidColorFont: { // Enable if something is selected. if (textBox1.SelectionLength > 0) cmdf |= OLECMDF.OLECMDF_ENABLED; break; } default: return (int)(Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED); } } else return (int)(Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED);
Note that only the SelectAll command is always enabled, whereas all the other commands are enabled only if text is selected, or some other condition is met.
The next step is to handle your commands in the Exec method. This method handles all of the commands that the Visual Studio Integration Package wizard generates, along with the Color Text command that is added in the Walkthrough: Adding a Command to an Editor Generated by the Package Wizard walkthrough. This step is illustrated in the code below:
Public Function Exec(ByRef guidCmdGroup As Guid, ByVal nCmdID As UInteger, ByVal nCmdexecopt As UInteger, _ ByVal pvaIn As System.IntPtr, ByVal pvaOut As System.IntPtr) As Integer Trace.WriteLine(String.Format(CultureInfo.CurrentCulture, "Entering Exec() of: {0}", Me.ToString())) If guidCmdGroup = VSConstants.GUID_VSStandardCommandSet97 Then ' Process standard Visual Studio Commands. Select Case nCmdID Case CUInt(VSStd97CmdID.Copy) textBox1.Copy() Exit Select Case CUInt(VSStd97CmdID.Cut) textBox1.Cut() Exit Select Case CUInt(VSStd97CmdID.Paste) textBox1.Paste() Exit Select Case CUInt(VSStd97CmdID.Redo) textBox1.Redo() Exit Select Case CUInt(VSStd97CmdID.Undo) textBox1.Undo() Exit Select Case CUInt(VSStd97CmdID.SelectAll) textBox1.SelectAll() Exit Select Case Else Return CInt(Fix(Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED)) End Select ElseIf guidCmdGroup = GuidList.guidTestEditorCmdSet Then Select Case nCmdID Case PkgCmdIDList.cmdidColorFont textBox1.SelectionColor = Color.Crimson Case Else Return CInt(Fix(Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED)) End Select Else Return CInt(Fix(Microsoft.VisualStudio.OLE.Interop.)) Constants.OLECMDERR_E_UNKNOWNGROUP End If Return VSConstants.S_OK End Function
public int Exec(ref Guid guidCmdGroup, uint nCmdID, uint nCmdexecopt, System.IntPtr pvaIn, System.IntPtr pvaOut) { Trace.WriteLine (string.Format(CultureInfo.CurrentCulture, "Entering Exec() of: {0}", this.ToString())); if (guidCmdGroup == VSConstants.GUID_VSStandardCommandSet97) { // Process standard Visual Studio Commands. switch (nCmdID) { case (uint)VSStd97CmdID.Copy: { textBox1.Copy(); break; } case (uint)VSStd97CmdID.Cut: { textBox1.Cut(); break; } case (uint)VSStd97CmdID.Paste: { textBox1.Paste(); break; } case (uint)VSStd97CmdID.Redo: { textBox1.Redo(); break; } case (uint)VSStd97CmdID.Undo: { textBox1.Undo(); break; } case (uint)VSStd97CmdID.SelectAll: { textBox1.SelectAll(); break; } default: return (int)(Microsoft.VisualStudio.OLE.Interop. Constants.OLECMDERR_E_NOTSUPPORTED); } } else if (guidCmdGroup == GuidList.guidTestEditorCmdSet) { switch (nCmdID) { case PkgCmdIDList.cmdidColorFont: textBox1.SelectionColor = Color.Crimson; break; default: return (int)(Microsoft.VisualStudio.OLE.Interop. Constants.OLECMDERR_E_NOTSUPPORTED); } } else return (int)Microsoft.VisualStudio.OLE.Interop. Constants.OLECMDERR_E_UNKNOWNGROUP; return VSConstants.S_OK; }