VSPackage 如何添加用户界面元素

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

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

Visual Studio 命令表体系结构

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

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

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

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

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

如何定义项

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

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

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

  • 定义在 UI 元素下并与元素名称 GuidSymbol 相匹配的 guid 属性。

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

guidid 属性共同组成 UI 元素的 签名

  • 一个 priority 属性,用于确定 UI 元素在其父菜单或组中的位置。

  • Parent 元素具有guidid属性,这些属性用于指定父菜单或组的签名。

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

  • 一个 type 属性,指定菜单是应以某种菜单还是工具栏的形式出现在 IDE 中。

  • 一个包含 ButtonText 元素Strings 元素,该元素指定 IDE 中菜单的标题,以及一个 CommandName 元素,该元素指定在命令窗口中用于访问菜单的名称。

  • 可选标志。 CommandFlag 元素可能出现在菜单定义中,以更改其在 IDE 中的外观或行为。

每个 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>

Groups

组是在部分的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

按钮在 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 部分中,或两者均具备) 可能包含(称为父级)
Groups 元素、IDE、其他 VSPackage 菜单、组、项本身 菜单、组和命令
菜单 Menus 元素、IDE、其他 VSPackage 1 到 n 个组 0 到 n 个组
工具栏 Menus 元素、IDE、其他 VSPackage 该项本身 0 到 n 个组
菜单项 Buttons 元素、IDE、其他 VSPackage 1 到 n 个组,项本身 -0 到 n 个组
Button Buttons 元素、IDE、其他 VSPackage 1 到 n 个组以及项本身
组合图 组合元素、IDE(集成开发环境)、其他 VSPackage 1 到 n 个组,以及项本身

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

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

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

命令可见性和上下文

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

可见性约束

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

VisibilityItem 元素必须具有三个属性,如下所示:目标 UI 元素的 guidid,以及 context。 该 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 标志结合使用。

有效期:ButtonComboMenu

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

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

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

应与 DefaultInvisible 标志结合使用。

有效期:ButtonComboMenu

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 中,除非该 UI 元素由其 VSPackage 对 QueryStatus 方法的实现显示,或与 VisibilityConstraints 部分中的特定 UI 上下文相关联。

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

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

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

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