如何:在 Vspackage (c#) 创建和处理命令

将命令添加到 VSPackage 过程分为两步。 首先,命令定义为 .vsct 文件的 XML 元素。 然后对代码中实现。 在 .vsct 文件输入的信息确定命令,其位置在集成开发环境 (ide) 和数组的 (IDE)外观行为。 命令在代码并定义,通常作为 MenuCommandOleMenuCommand 对象,并且,其事件处理程序中实现。

VSPackage 可 IDE 的命令必须是显示并启用,用户可以使用它们。 使用 Visual Studio 包 " 项目模板时,命令在 .vsct 文件创建默认情况下,它们是显示并启用。 设置某些命令标志,例如 DynamicItemStart,可以更改默认行为。 可见性、启用状态和命令的其他属性在运行时的代码还能更改被访问与命令的 OleMenuCommand 对象。

创建命令

所有命令、命令组、菜单、工具栏和工具窗口。 .vsct 文件中定义的。 如果 VSPackage 没有 .vsct 文件,必须添加一个。 有关更多信息,请参见 Visual Studio 命令 (表。Vsct) 文件

使用包模板,如果创建 VSPackage 中,选择 菜单命令 创建 .vsct 文件和定义默认菜单命令。 有关更多信息,请参见 演练:使用 Visual Studio 创建包模板的菜单命令

将命令添加到 IDE

  1. 打开 .vsct 文件。

  2. 在 Symbols 部分,找到包含组和命令的 GuidSymbol 元素。

  3. 创建每个菜单,组一个 IDSymbol 元素或命令要添加,如下面的示例所示,。

    <GuidSymbol name="guidButtonGroupCmdSet" value="{f69209e9-975a-4543-821d-1f4a2c52d737}">
      <IDSymbol name="MyMenuGroup" value="0x1020" />
      <IDSymbol name="cmdidMyCommand" value="0x0100" />
    </GuidSymbol>
    

    GuidSymbol 和 IDSymbol 元素的 name 属性提供 GUID: ID 为每个新菜单、组或命令对。 guid 表示为 VSPackage 定义设置的命令。 您可以定义多个命令设置。 每个 GUID: ID 匹配必须是唯一的。

  4. ,如下面的示例所示 按钮 部分中,创建一个 按钮 元素定义命令,。

    <Button guid="guidButtonGroupCmdSet" id="cmdidMyCommand" priority="0x0100" type="Button">
      <Parent guid="guidButtonGroupCmdSet" id="MyMenuGroup" />
      <Icon guid="guidImages" id="bmpPic1" />
      <Strings>
        <CommandName>cmdidMyCommand</CommandName>
        <ButtonText>My Command name</ButtonText>
      </Strings>
    </Button>
    
    1. 设置 guid ,并 id 字段匹配 GUID: 新的命令 ID。

    2. 设置 priority 特性。

      该 .vsct 用于 priority 属性确定按钮的位置在其他对象中的在其父组中。

      较低优先级的值显示的命令中,或在左边,具有较高优先级的值的命令。 重复优先级值,允许,但相同优先级 Vspackage 处理在运行时,因此,命令无法预先确定的顺序由命令的相对位置。

      省略 priority 属性将其值设置为 0。

    3. 设置 type 特性。 在大多数情况下,其值将为 “按钮”。 有关其他活动按钮类型的说明,请参见 Button 元素

  5. 在按钮定义,请创建一个包含 ButtonText 元素包含菜单的一个 字符串 元素,它会显示 IDE 和 CommandName 元素的名称包含命令的名称用于访问菜单中 命令 窗口。

    如果按钮文本字符串中包含 " 字符,用户可以通过按 alt 键打开菜单以及紧跟在 " 的字符。

    添加 Tooltip 元素将导致该包含的文本显示用户将鼠标指针悬停在按钮的指针。

  6. 添加一个 图标 元素指定图标,如果有,则会显示与该命令。 图标所需的工具栏中的按钮,但不适用于菜单项。 Icon 元素的 guid 和 id 必须与 Bitmaps 部分定义的那些 位图 元素。

  7. 添加命令标志,根据需要,更改按钮的外观和行为。 为此,请添加到菜单定义的一个 CommandFlag 元素。

  8. 将该命令的父组。 父组可以是您创建的组,从另一个包的一组或者从 IDE 的一组。 例如,添加命令到编辑器工具栏的 Visual Studio 中,在 注释移除注释 按钮旁边的按钮,设置父到 guidStdEditor: IDG_VS_EDITTOOLBAR_COMMENT. 如果父是一个用户定义的组,它必须是显示在 IDE 菜单、工具栏或工具窗口的子级。

    可以基于模型执行此以下两种方法之一,例如:

    • 在 Button 元素中,创建一个 元素并将其 guid 和 id 字段设置为将承载该命令组的 GUID 和 ID,也称为 主父组。

      下面的示例定义一个将显示在用户定义的菜单上的命令。

      <Button guid="guidTopLevelMenuCmdSet" id="cmdidTestCommand" priority="0x0100" type="Button">
        <Parent guid="guidTopLevelMenuCmdSet" id="MyMenuGroup" />
        <Icon guid="guidImages" id="bmpPic1" />
        <Strings>
          <CommandName>cmdidTestCommand</CommandName>
          <ButtonText>Test Command</ButtonText>
        </Strings>
      </Button>
      
    • 使用命令,位置,因此,如果命令将确定您可以省略 Parent 元素。 ,如下面的示例所示 Symbols 部分之前创建一个 CommandPlacements 元素,并添加具有命令、 priority和父级的 guid 和 id 的 CommandPlacement 元素,。

      <CommandPlacements>
        <CommandPlacement guid="guidButtonGroupCmdSet" id="cmdidMyCommand" priority="0x105">
          <Parent guid="guidButtonGroupCmdSet" id="MyMenuGroup" />
        </CommandPlacement>
      </CommandPlacements>
      

      创建具有相同的 GUID 的多个命令位置: ID 和具有不同的父原因出现的菜单于多个位置。 有关更多信息,请参见 CommandPlacements 元素。

    有关命令组和权的更多信息,请参见 如何:为按钮创建可重用的组

此时,该命令会显示在 IDE,但是,不会将功能。 如果命令是由包模板创建的,则默认情况下它将具有显示消息中单击处理程序。

处理新的命令

在托管代码中的大多数命令可由管理的包结构 (MPF)处理通过将该命令与 MenuCommand 对象或 OleMenuCommand 对象和实现其事件处理程序。

为直接用于处理指令使用 IOleCommandTarget 接口的代码,必须执行 IOleCommandTarget 接口及其方法。 两个最重要的方法是 QueryStatusExec

处理使用 MPF 的新命令

  1. 获取 OleMenuCommandService 实例,如以下示例所示。

    OleMenuCommandService mcs = 
        GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
    
  2. 如下面的示例所示,创建具有作为其参数命令 GUID 和 ID 处理的一 CommandID 对象,。

    CommandID menuCommandID = 
        new CommandID(GuidList.guidButtonGroupCmdSet, 
            (int)PkgCmdIDList.cmdidMyCommand);
    

    Visual Studio 包模板提供两个集合、 GuidList 和 PkgCmdIDList,保存命令 GUID 和 ID。 这些为由模板添加的命令自动填充,但是,对于命令手动添加,还必须将 ID 项。 PkgCmdIdList 类。

    或者,可以使用 GUID 的原始字符串值和 ID.,的整数值可以填充 CommandID 对象

  3. 实例化指定方法处理与 CommandID一起的命令,如下面的示例所示的 MenuCommandOleMenuCommand 对象。

    MenuCommand menuItem = 
        new MenuCommand(MenuItemCallback, menuCommandID);
    

    MenuCommand 为静态命令正确。 动态菜单项显示需要 QueryStatus 事件处理程序。 OleMenuCommand 添加 BeforeQueryStatus 事件,发生,打开后命令的宿主菜单和其他一些属性,如 Text

    包模板创建的默认命令传递到包类的 Initialize() 方法的一 OleMenuCommand 对象。

  4. MenuCommand 为静态命令正确。 动态菜单项显示需要 QueryStatus 事件处理程序。 OleMenuCommand 添加 BeforeQueryStatus 事件,发生,打开后命令的宿主菜单和其他一些属性,如 Text

    包模板创建的默认命令传递到包类的 Initialize() 方法的一 OleMenuCommand 对象。 使用 MenuCommand, Visual Studio 向导执行 Initialize 方法。 对动态菜单项所示,您需要将它更改为 OleMenuCommand,如下一步显示。 此外,将菜单项文本,您必须添加 TextChanges 命令标志到 .vsct 文件的菜单命令按钮,如下面的示例所示

    <Button guid="guidMenuTextCmdSet" id="cmdidMyCommand" priority="0x0100" type="Button">
      <Parent guid="guidMenuTextCmdSet" id="MyMenuGroup" />
      <Icon guid="guidImages" id="bmpPic1" />
      <CommandFlag>TextChanges</CommandFlag>
      <Strings>
        <CommandName>cmdidMyCommand</CommandName>
        <ButtonText>My Command name</ButtonText>
      </Strings>
    </Button>
    
  5. 将新菜单命令对 IMenuCommandService 接口的 AddCommand 方法。 默认情况下将为该包模板创建的命令完成,如下面的示例所示。

    mcs.AddCommand( menuItem );
    
  6. 执行该方法处理命令。

使用 MPF 类,该类实现 QueryStatus

  1. ,在显示的命令之前, QueryStatus 事件发生。 ,在到达用户之前,会在事件处理程序启用该命令属性设置。 添加了唯一的顺序,当 OleMenuCommand 对象访问此方法。

    BeforeQueryStatus 事件 EventHandler 对象在创建处理命令的 OleMenuCommand 对象,如下面的示例所示 (menuItem 是 OleMenuCommand 实例)。

    Dim menuCommandID As CommandID = New CommandID(GuidList.guidMenuTextCmdSet, CInt(PkgCmdIDList.cmdidMyTextCommand))
    Dim menuItem As OleMenuCommand = New OleMenuCommand(New EventHandler(AddressOf MenuItemCallback), menuCommandID)
    AddHandler menuItem.BeforeQueryStatus, AddressOf OnBeforeQueryStatus
    mcs.AddCommand(menuItem)
    
    // Create the command for the menu item.
    CommandID menuCommandID = new CommandID(GuidList.guidMenuTextCmdSet, (int)PkgCmdIDList.cmdidMyCommand);
    OleMenuCommand menuItem = new OleMenuCommand(MenuItemCallback, menuCommandID );
    menuItem.BeforeQueryStatus +=
        new EventHandler(OnBeforeQueryStatus);
    mcs.AddCommand(menuItem);
    

    将调用 EventHandler 对象方法的名称,当菜单命令的状态将查询时。

  2. 执行命令的查询状态处理程序方法。 object sender 参数可转换为一 OleMenuCommand 对象,用于将菜单命令的各个属性,包括该文本。 下表显示了 MenuCommand 类的属性 (对应于 OLECMDF 标志的哪些 MPF 类 OleMenuCommand 从派生)。

    MenuCommand 属性

    OLECMDF 标志

    Checked = true

    OLECMDF_LATCHED

    Visible = false

    OLECMDF_INVISIBLE

    Enabled = true

    OLECMDF_ENABLED

    如下面的示例所示,若要更改菜单命令的文本,请使用在 OleMenuCommand 对象的属性, Text

    Private Sub OnBeforeQueryStatus(ByVal sender As Object, ByVal e As EventArgs)
        Dim myCommand As OleMenuCommand = TryCast(sender, OleMenuCommand)
        If myCommand IsNot Nothing Then
            myCommand.Text = "New Text" 
        End If 
    End Sub
    
    private void OnBeforeQueryStatus(object sender, EventArgs e)
    {
        var myCommand = sender as OleMenuCommand;
        if (null != myCommand)
        {
            myCommand.Text = "New Text";
        }
    }
    

自动 MPF 处理大小写不支持或未知的组。 使用 AddCommand 方法,除非命令添加到 OleMenuCommandService ,命令不受支持。

处理使用 IOleCommandTarget 接口的命令

为直接使用 IOleCommandTarget 接口的代码, VSPackage 必须执行 QueryStatusIOleCommandTarget 接口的 Exec 方法。 如果 VSPackage 实现一个项目层次结构,应执行 IVsUIHierarchy 接口的 QueryStatusCommandExecCommand 方法。

QueryStatusExec 方法旨在收到一条命令设置的 GUID 和数组命令 ID 作为输入。 建议 Vspackage 完全支持多个 ID 的此概念在一个中调用。 但是,在中,只要 VSPackage 不会从其他 Vspackage 调用,可以假定,命令数组只包含命令 ID,因为 QueryStatusExec 方法以定义完善的顺序执行。 有关路由的更多信息,请参见 Command Routing in VSPackages

为直接用于处理指令使用 IOleCommandTarget 接口的代码,必须按如下方式执行在 VSPackage 中 QueryStatus 方法处理命令。

执行 QueryStatus 方法

  1. 返回有效的命令 S_OK

  2. 设置 prgCmds 参数的 cmdf 元素。

    cmdf 元素的值是逻辑联合从 OLECMDF 枚举的,将使用逻辑或 (|) 运算符。

    根据命令的状态使用相应的枚举,例如:

    • 如果命令支持:

      prgCmds[0].cmdf = OLECMDF_SUPPORTED;

    • 如果命令应当时是不可见的:

      prgCmds[0].cmdf |= OLECMDF_INVISIBLE;

    • 如果命令切换并出现单击了:

      prgCmds[0].cmdf |= OLECMDF_LATCHED;

      在处理在类型 MenuControllerLatched菜单上的命令,由 OLECMDF_LATCHED 标志指示的第一个命令为启动的菜单中显示的默认命令。 有关 MenuController 菜单类型的更多信息,请参见 Menu 元素

    • 命令当前活动:

      prgCmds[0].cmdf |= OLECMDF_ENABLED;

    • 默认情况下将命令是快捷菜单的一部分和隐藏:

      prgCmds[0] cmdf |= OLECMDF_DEFHIDEONCTXMENU

    • 如果命令使用 TEXTCHANGES 标志,设置 pCmdText 参数的 rgwz 元素到命令的新文本并将 pCmdText 参数的 cwActual 元素到命令字符串的大小。

    对错误状态, QueryStatus 方法必须处理以下错误情况:

    • 如果 GUID 未知或不支持,则返回 OLECMDERR_E_UNKNOWNGROUP。

    • 如果 GUID 知道,但命令 ID 未知或不支持,则返回 OLECMDERR_E_NOTSUPPORTED。

Exec 方法的 VSPackage 实现还必须返回特定错误代码,根据命令是否支持,而命令是否已成功处理。

执行 exec 方法

  • 如果命令 GUID 是未知的,请返回 OLECMDERR_E_UNKNOWNGROUP。

  • 如果 GUID 是已知的,但命令 ID 是未知的,请返回 OLECMDERR_E_NOTSUPPORTED。

  • 如果 GUID 和命令 ID 匹配 GUID: 命令使用在 .vsct 文件的 ID 匹配,执行与命令的代码并返回 S_OK

请参见

概念

VSCT XML 架构参考

其他资源

使用命令、菜单和工具栏的常规任务

Walkthrough: Adding a Command to a Visual Studio Menu