VSPackage 如何添加用户界面元素

VSPackage 可以通过 .vsct 文件将用户界面(UI)元素(例如菜单、工具栏和工具窗口)添加到 Visual Studio

可以在 Visual Studio 用户体验指南中找到 UI 元素的设计准则

Visual Studio 命令表体系结构

如前所述,命令表体系结构支持上述体系结构原则。 命令表体系结构的抽象、数据结构和工具背后的原则如下所示:

  • 有三种基本类型的项:菜单、命令和组。 菜单可以在 UI 中作为菜单、子菜单、工具栏或工具窗口公开。 命令是用户可以在 IDE 中执行的过程,它们可以作为菜单项、按钮、列表框或其他控件公开。 组是菜单和命令的容器。

  • 每个项都由一个定义来指定,该定义描述项的优先级相对于其他项,以及修改其行为的标志。

  • 每个项都有一个描述项父项的位置。 一个项可以有多个父项,以便它可以显示在 UI 中的多个位置。

每个命令都必须有一个组作为其父级,即使它是该组中唯一的子级也是如此。 每个标准菜单还必须有一个父组。 工具栏和工具窗口充当自己的父级。 组可以具有其父级 Visual Studio 菜单栏,或任何菜单、工具栏或工具窗口。

如何定义项

.vsct 文件采用 XML 格式。 它定义包的 UI 元素,并确定这些元素在 IDE 中的显示位置。 首先为包中的每个菜单、组或命令分配一个 GUID 和 ID Symbols 。 在整个 .vsct 文件的其余部分,每个菜单、命令和组都由其 GUID 和 ID 组合标识。 以下示例演示在模板中选择菜单命令Visual Studio 包模板生成的典型Symbols部分。

<Symbols>
  <!-- This is the package guid. -->
  <GuidSymbol name="guidMenuTextPkg" value="{b1253bc6-d266-402b-89e7-5e3d3b22c746}" />

  <!-- This is the guid used to group the menu commands together -->
  <GuidSymbol name="guidMenuTextCmdSet" value="{a633d4e4-6c65-4436-a138-1abeba7c9a69}">
    <IDSymbol name="MyMenuGroup" value="0x1020" />
    <IDSymbol name="cmdidMyCommand" value="0x0100" />
  </GuidSymbol>

  <GuidSymbol name="guidImages" value="{53323d9a-972d-4671-bb5b-9e418480922f}">
    <IDSymbol name="bmpPic1" value="1" />
    <IDSymbol name="bmpPic2" value="2" />
    <IDSymbol name="bmpPicSearch" value="3" />
    <IDSymbol name="bmpPicX" value="4" />
    <IDSymbol name="bmpPicArrows" value="5" />
  </GuidSymbol>
</Symbols>

节的 Symbols 顶级元素是 GuidSymbol 元素GuidSymbol 元素将名称映射到 IDE 用来标识包及其组件部件的 GUID。

注意

GUID 由 Visual Studio 包模板自动生成。 还可以通过单击“工具”菜单上的“创建 GUID”来创建唯一 GUID

第一个 GuidSymbol 元素 guid<PackageName>Pkg是包本身的 GUID。 这是 Visual Studio 用于加载包的 GUID。 通常,它没有子元素。

按照约定,菜单和命令分组在第二 GuidSymbol 个元素下, guid<PackageName>CmdSet位图位于第三 GuidSymbol 个元素 guidImages下。 无需遵循此约定,但每个菜单、组、命令和位图都必须是元素的 GuidSymbol 子级。

第二 GuidSymbol 个表示包命令集的元素是多个 IDSymbol 元素。 每个 IDSymbol 元素 将名称映射到数值,并可能表示属于命令集的菜单、组或命令。 第 IDSymbolGuidSymbol 个元素中的元素表示可用作命令图标的位图。 由于 GUID/ID 对在应用程序中必须是唯一的,因此同 GuidSymbol 一元素的两个子级可能具有相同的值。

当菜单、组或命令具有 GUID 和 ID 时,可以将其添加到 IDE。 每个 UI 元素必须具有以下各项:

  • guid UI 元素所定义的元素名称 GuidSymbol 匹配的属性。

  • id 关联 IDSymbol 元素的名称匹配的属性。

组合在 guid 一起,属性 id 构成 UI 元素的签名

每个菜单都定义为分区中的 Menus Menu 元素。 菜单必须具有guidid属性和priorityParent元素,以及以下附加属性和子元素:

每个 Menu 元素都必须有一个组作为其父级,除非它是可停靠的元素,如工具栏。 可停靠菜单是其自己的父菜单。 有关属性的 type 菜单和值的详细信息,请参阅 Menu 元素 文档。

以下示例显示显示在“工具”菜单旁边的 Visual Studio 菜单栏上的菜单。

<Menu guid="guidTopLevelMenuCmdSet" id="TopLevelMenu" priority="0x700" type="Menu">
  <Parent guid="guidSHLMainMenu" id="IDG_VS_MM_TOOLSADDINS" />
  <Strings>
    <ButtonText>TestMenu</ButtonText>
    <CommandName>TestMenu</CommandName>
  </Strings>
</Menu>

组是在 .vsct 文件的节Groups定义的项。 组只是容器。 它们不会显示在 IDE 中,只是菜单上的分隔线。 因此, Group 元素仅由其签名、优先级和父元素 定义。

组可以有一个菜单、另一个组或本身作为父级。 但是,父级通常是菜单或工具栏。 前面的示例中的菜单是组的 IDG_VS_MM_TOOLSADDINS 子级,该组是 Visual Studio 菜单栏的子级。 以下示例中的组是前面示例中菜单的子级。

<Group guid="guidTopLevelMenuCmdSet" id="MyMenuGroup" priority="0x0600">
  <Parent guid="guidTopLevelMenuCmdSet" id="TopLevelMenu"/>
</Group>

由于它是菜单的一部分,因此此组通常包含命令。 但是,它还可能包含其他菜单。 这就是如何定义子菜单,如以下示例所示。

<Menu guid="guidTopLevelMenuCmdSet" id="SubMenu" priority="0x0100" type="Menu">
  <Parent guid="guidTopLevelMenuCmdSet" id="MyMenuGroup"/>
  <Strings>
    <ButtonText>Sub Menu</ButtonText>
    <CommandName>Sub Menu</CommandName>
  </Strings>
</Menu>

命令

提供给 IDE 的命令定义为 Button 元素组合元素。 若要显示在菜单或工具栏上,该命令必须具有一个组作为其父级。

按钮

按钮 Buttons 在节中定义。 用户单击执行单个命令的任何菜单项、按钮或其他元素都被视为按钮。 某些按钮类型还可以包括列表功能。 按钮具有菜单具有的相同必需属性和可选属性,还可以具有一个 Icon 元素,该元素 指定表示 IDE 中按钮的位图的 GUID 和 ID。 有关按钮及其属性的详细信息,请参阅 Buttons 元素 文档。

以下示例中的按钮是前面示例中组的子级,该组的父菜单上将显示为 IDE 中的菜单项。

<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>
组合

组合在节中 Combos 定义。 每个 Combo 元素表示 IDE 中的下拉列表框。 列表框可能由用户写入,具体取决于组合的属性的值 type 。 组合具有按钮具有的相同元素和行为,还可以具有以下附加属性:

  • 一个 defaultWidth 指定像素宽度的属性。

  • idCommandList 个属性,指定包含列表框中显示的项的列表。 命令列表必须在包含组合的同一 GuidSymbol 节点中声明。

以下示例定义组合元素。

<Combos>
  <Combo guid="guidFirstToolWinCmdSet"
         id="cmdidWindowsMediaFilename"
         priority="0x0100" type="DynamicCombo"
         idCommandList="cmdidWindowsMediaFilenameGetList"
         defaultWidth="130">
    <Parent guid="guidFirstToolWinCmdSet"
            id="ToolbarGroupID" />
    <CommandFlag>IconAndText</CommandFlag>
    <CommandFlag>CommandWellOnly</CommandFlag>
    <CommandFlag>StretchHorizontally</CommandFlag>
    <Strings>
      <CommandName>Filename</CommandName>
      <ButtonText>Enter a Filename</ButtonText>
    </Strings>
  </Combo>
</Combos>
位图

将与图标一起显示的命令必须包含一个 Icon 元素,该元素使用位图的 GUID 和 ID 来引用位图。 每个位图都定义为节中的Bitmaps位图元素。 定义的唯一 Bitmap 必需属性是 guid 指向源文件并 href指向源文件。 如果源文件是资源条带, 则还需要使用 usedList 属性列出条带中的可用图像。 有关详细信息,请参阅 Bitmap 元素 文档。

设为父级

以下规则控制项如何调用另一项作为其父项。

元素 在命令表的本节中定义 可以包含(作为父级,或按在节中 CommandPlacements 放置或同时包含) 可以包含(称为父级)
Group Groups 元素、IDE、其他 VSPackage 菜单、组、项本身 菜单、组和命令
菜单 Menus 元素、IDE、其他 VSPackage 1 到 n 个组 0 到 n 个组
Toolbar Menus 元素、IDE、其他 VSPackage 项本身 0 到 n 个组
菜单项 Buttons 元素、IDE、其他 VSPackage 1 到 n 个组,项本身 -0 到 n 个组
Button Buttons 元素、IDE、其他 VSPackage 1 到 n 个组,项本身
组合图 组合元素、IDE、其他 VSPackage 1 到 n 个组,项本身

菜单、组或命令可以出现在 IDE 中的多个位置。 要使项出现在多个位置,必须将该项作为 CommandPlacement 元素添加到CommandPlacements中。 任何菜单、组或命令都可以添加为命令放置。 但是,工具栏不能以这种方式定位,因为它们不能出现在多个上下文敏感位置。

命令放置具有 guidid属性和 priority 属性。 GUID 和 ID 必须与定位的项的 ID 匹配。 该 priority 属性控制项目与其他项的放置。 当 IDE 合并具有相同优先级的两个或多个项时,它们的位置是未定义的,因为 IDE 不能保证每次生成包时按相同的顺序读取包资源。

如果菜单或组出现在多个位置,则该菜单或组的所有子级将显示在每个实例中。

命令可见性和上下文

安装多个 VSPackage 时,菜单、菜单项和工具栏的大量内容可能会让 IDE 混乱。 若要避免此问题,可以使用可见性约束和命令标志来控制单个 UI 元素的可见性。

可见性约束

可见性约束设置为节中的 VisibilityConstraints VisibilityItem 元素。 可见性约束定义目标项可见的特定 UI 上下文。 仅当其中一个定义的上下文处于活动状态时,本节中包含的菜单或命令才可见。 如果本节中未引用菜单或命令,则默认情况下它始终可见。 本部分不适用于组。

VisibilityItem 元素必须具有三个属性,如下所示: guid 目标 UI 元素和 idcontext。 该 context 属性指定目标项何时可见,并将任何有效的 UI 上下文作为其值。 Visual Studio 的 UI 上下文常量是类的成员 VSConstants 。 每个 VisibilityItem 元素只能采用一个上下文值。 若要应用第二个上下文,请创建指向同一项的第二 VisibilityItem 个元素,如以下示例所示。

<VisibilityConstraints>
  <VisibilityItem guid="guidSolutionToolbarCmdSet"
        id="cmdidTestCmd"
        context="UICONTEXT_SolutionHasSingleProject" />
  <VisibilityItem guid="guidSolutionToolbarCmdSet"
        id="cmdidTestCmd"
        context="UICONTEXT_SolutionHasMultipleProjects" />
</VisibilityConstraints>

命令标志

以下命令标志可能会影响菜单的可见性以及它们所适用的命令。

AlwaysCreate 即使没有组或按钮,也会创建菜单。

有效期: Menu

CommandWellOnly 如果命令未显示在顶级菜单上,并且希望使其可用于其他 shell 自定义,例如,将其绑定到键,则应用此标志。 安装 VSPackage 后,用户可以通过打开“选项”对话框,然后在键盘环境类别下编辑命令放置来自定义这些命令。 不影响快捷菜单、工具栏、菜单控制器或子菜单的放置。

有效期: ButtonCombo

DefaultDisabled 默认情况下,如果未加载实现命令的 VSPackage 或未调用 QueryStatus 方法,则会禁用该命令。

有效期: ButtonCombo

DefaultInvisible 默认情况下,如果未加载实现该命令的 VSPackage 或未调用 QueryStatus 方法,则命令不可见。

应与 DynamicVisibility 标志结合使用。

有效期: Button, , ComboMenu

DynamicVisibility 可以使用 QueryStatus 该节中包含的 VisibilityConstraints 方法或上下文 GUID 来更改命令的可见性。

适用于菜单而不是工具栏上显示的命令。 当从QueryStatus方法返回标志时OLECMDF_INVISIBLE,可以禁用顶级工具栏项,但不能隐藏。

在菜单上,此标志还指示当其成员处于隐藏状态时,它应自动隐藏。 此标志通常分配给子菜单,因为顶级菜单已具有此行为。

应与 DefaultInvisible 标志结合使用。

有效期: Button, , ComboMenu

NoShowOnMenuController 如果具有此标志的命令位于菜单控制器上,该命令不会显示在下拉列表中。

有效期: Button

有关命令标志的详细信息,请参阅 CommandFlag 元素 文档。

一般要求

命令必须通过以下一系列测试,然后才能显示和启用它:

  • 命令已正确定位。

  • DefaultInvisible未设置标志。

  • 父菜单或工具栏可见。

  • 由于 VisibilityConstraints 元素部分中的上下文条目,该命令不可见。

  • 实现接口的 IOleCommandTarget VSPackage 代码显示并启用命令。 没有接口代码截获并对其执行操作。

  • 当用户单击命令时,它会受到路由算法概述的过程的约束。

调用预定义命令

UsedCommands 元素使 VSPackages 能够访问由其他 VSPackage 或 IDE 提供的命令。 为此,请创建 具有要使用的命令的 GUID 和 ID 的 UsedCommand 元素 。 这可确保命令将由 Visual Studio 加载,即使它不是当前 Visual Studio 配置的一部分。 有关详细信息,请参阅 UsedCommand 元素

接口元素外观

选择和定位命令元素的注意事项如下:

  • Visual Studio 提供了许多 UI 元素,这些元素因位置而异。

  • 通过使用 DefaultInvisible 标志定义的 UI 元素将不会显示在 IDE 中,除非由该方法的 QueryStatus VSPackage 实现显示,或与节中的 VisibilityConstraints 特定 UI 上下文相关联。

  • 甚至可能不会显示成功定位的命令。 这是因为 IDE 会自动隐藏或显示某些命令,具体取决于 VSPackage 实现的接口(或尚未实现)。 例如,VSPackage 对某些生成接口的实现会导致自动显示与生成相关的菜单项。

  • CommandWellOnly UI 元素的定义中应用标志意味着命令只能通过自定义添加。

  • 命令只能在某些 UI 上下文中使用,例如,仅在 IDE 处于设计视图中时显示对话框时才可用。

  • 若要使某些 UI 元素显示在 IDE 中,必须实现一个或多个接口或编写一些代码。