如何:向快捷菜单中添加命令

可以将菜单命令添加到域特定语言 (DSL),以便用户可以执行特定于 DSL 的任务。命令显示在上下文 (快捷) 菜单,当用户在关系图中右击。可以定义命令,以便在特定情况下只出现在菜单。例如,您可以使该在特定状态的命令可见,只有当用户单击组件的特定类型,或者元素。

总之,步骤。 DslPackage 项目执行,如下所示:

  1. 声明在 Commands.vsct 的命令

  2. 更新在 Package.tt 的包版本号。必须执行此操作,无论更改 Commands.vsct

  3. 使命令可见并确定的在 CommandSet 类中编写方法 要命令执行。

有关示例,请参见 Visualization and Modeling SDK website

说明说明

可以修改某个现有命令行为 (如剪切,粘贴,选择所有和通过重写的方法中打印 CommandSet.cs。有关更多信息,请参见 如何:使用域特定语言修改标准的菜单命令

定义使用 MEF 的命令

托管扩展框架在 (MEF)关系图菜单提供定义菜单命令的另一种方法。其主要目的是使 DSL 扩展由您或其他用户。用户选择安装 DSL 或可以安装 DSL 和扩展。但是, MEF 在初始工作后还可以减少定义快捷菜单命令工作,启用 DSL 的 MEF。

请使用方法在本主题中,如果:

  1. 除了右击快捷菜单外,要定义在菜单的菜单命令。

  2. 要定义命令特定分组在菜单上的。

  3. 您不要使其他扩展它们的命令 DSL。

  4. 您只需定义一个命令。

否则,请考虑使用 MEF 方法定义命令。有关更多信息,请参见 使用 MEF 扩展 DSL

声明在 Commands.Vsct 的命令

菜单命令在 DslPackage \Commands .vsct 声明。这些定义指定菜单项的标签,它们将出现在菜单的位置。

正在编辑的文件, Commands.vsct,导入定义几个 .h 文件,位于目录 Visual Studio SDK 安装路径\VisualStudioIntegration\Common\Inc。它还包括 GeneratedVsct.vsct,从 DSL 定义生成。

有关 .vsct 文件的更多信息,请参见 Visual Studio 命令 (表。Vsct) 文件

添加命令

  1. 解决方案资源管理器,在 DslPackage 项目中,打开 Commands.vsct。

  2. 在 Commands 元素,请定义一个或多个按钮和一组。按钮 位于菜单的项目。组 是在菜单的一部分。若要定义这些项目中,添加以下元素:

    <!-- Define a group - a section in the menu -->
    <Groups>
      <Group guid="guidCustomMenuCmdSet" id="grpidMyMenuGroup" priority="0x0100">
        <!-- These symbols are defined in GeneratedVSCT.vsct -->
        <Parent guid="guidCmdSet" id="menuidContext" />
      </Group>
    </Groups>
    <!-- Define a button - a menu item - inside the Group -->
    <Buttons>
      <Button guid="guidCustomMenuCmdSet" id="cmdidMyContextMenuCommand"
        priority="0x0100" type="Button">
        <Parent guid="guidCustomMenuCmdSet" id="grpidMyMenuGroup"/>
        <!-- If you do not want to place the command in your own Group, 
             use Parent guid="guidCmdSet" id="grpidContextMain".
             These symbols are defined in GeneratedVSCT.vsct -->
        <CommandFlag>DynamicVisibility</CommandFlag>
        <Strings>
          <ButtonText>My Context Menu Command</ButtonText>
        </Strings>
      </Button>
    </Buttons>
    
    说明说明

    每个按钮或组由 GUID 和整数 ID. 定位可以使用同样的 GUID 创建多个组和按钮。但是,它们必须具有不同的 ID。GUID 名称和 ID 名称被转换为实际 GUID 和数值 ID。 Symbols 节点。

  3. 添加命令的可见性约束,以便仅加载在这种域特定语言中。有关更多信息,请参见 VisibilityConstraints 元素

    为此,请在 Commands 元素之后添加到 CommandTable 元素的以下元素。

    <VisibilityConstraints>
      <!-- Ensures the command is only loaded for this DSL -->
      <VisibilityItem guid="guidCustomMenuCmdSet" id="cmdidMyContextMenuCommand"
        context="guidEditor"/>
    </VisibilityConstraints>
    
  4. 定义为 GUID 和 ID 使用的名称。为此,请在 Commands 元素之后添加到 CommandTable 元素的一个 Symbols 元素。

    <Symbols>
      <!-- Substitute a unique GUID for the placeholder: -->
      <GuidSymbol name="guidCustomMenuCmdSet"
        value="{00000000-0000-0000-0000-000000000000}" >
        <IDSymbol name="grpidMyMenuGroup" value="0x01001"/>
        <IDSymbol name="cmdidMyContextMenuCommand" value="0x00001"/>
      </GuidSymbol>
    </Symbols>
    
  5. 用标识组和菜单项的 GUID 替换 {000...000} 。若要获取新的 GUID,请使用在 工具 菜单的 创建 GUID 工具。

    说明说明

    如果您添加更多组或菜单项,则可以使用相同的 GUID。但是,必须为 IDSymbols使用新值。

  6. 在您从该程序复制的代码,请用替换以下字符串的每个匹配项拥有字符串:

    • grpidMyMenuGroup

    • cmdidMyContextMenuCommand

    • guidCustomMenuCmdSet

    • 我的上下文菜单命令

更新在 Package.tt 的包版本

每次添加或更改一个命令,请更新应用于包类 ProvideMenuResourceAttribute 的 version 参数,在释放域特定语言之前的新版本。

由于包类在生成的文件中定义,更新在生成 Package.cs 文件的文本模板文件的属性。

更新 Package.tt 文件

  1. 解决方案资源管理器,在 DslPackage 项目,在 GeneratedCode 文件夹中,打开 Package.tt 文件。

  2. 找到 ProvideMenuResource 属性。

  3. 增加属性的 version 参数,是第二个参数。如果需要,可以编写显式提醒您的参数名它的用途。例如:

    [VSShell::ProvideMenuResource("1000.ctmenu", version: 2 )]

定义命令的行为

DSL 已在分部类中实现。 DslPackage \GeneratedCode\CommandSet .cs 声明的某些命令。若要添加新命令,您必须通过创建包含同一类的分部声明的新文件扩展此类。类的名称通常是 YourDslNameCommandSet。通过验证类的名称并检查其内容启动很有用。

命令设置的类从 CommandSet派生。

扩展 CommandSet 类

  1. 在解决方案资源管理器中, DslPackage 项目中,打开 GeneratedCode 文件夹中查找在 CommandSet.tt 下并打开其生成的文件 CommandSet.cs。请注意命名空间和其中定义在该处质数的名称。例如,您可能会发现:

    namespace Company.Language1

    { ... internal partial class Language1CommandSet : ...

  2. DslPackage,请创建一个名为 " " 的文件夹。此文件夹中,创建名为 CommandSet.cs的新的类文件。

  3. 在新文件,编写具有命名空间和名称以及生成的分部类相同的分部声明。例如:

    namespace Company.Language1 /* Make sure this is correct */

    { internal partial class Language1CommandSet { ...

    请注意,如果您在使用类模板创建新文件,必须更正命名空间和类名。

Dd820681.collapse_all(zh-cn,VS.110).gif扩展命令设置的类

命令设置的代码通常需要导入下列命名空间:

using System;
using System.Collections.Generic;
using System.ComponentModel.Design; 
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Shell;

调整命名空间和类名匹配在生成的 CommandSet.cs:

namespace Company.Language1 /* Make sure this is correct */
{
  // Same class as the generated class.
  internal partial class Language1CommandSet 
  {

必须定义两个方法,则确定命令何时可见在上下文菜单和执行命令的其他。这些方法不是重写;相反,您注册它们在命令列表。

Dd820681.collapse_all(zh-cn,VS.110).gif,在命令将可见,请定义

对于每个命令,请定义一个用于确定 OnStatus... 方法命令是否将出现在菜单,因此,它是否启用或灰色。如下面的示例所示,设置 MenuCommand的 Visible 和 Enabled 属性,。调用此方法以便每次构造快捷菜单用户右击关系图,因此,它必须快速工作。

在此示例中,命令可见,仅当用户选定形状中的特定类型并且启用了,则仅当至少一个所选元素处于特定状态时。此示例基于类图 DSL 模板,因此, ClassShape 和 ModelClass 是在 DSL 定义的类型:

private void OnStatusMyContextMenuCommand(object sender, EventArgs e)
{
  MenuCommand command = sender as MenuCommand;
  command.Visible = command.Enabled = false;
  foreach (object selectedObject in this.CurrentSelection)
  {
    ClassShape shape = selectedObject as ClassShape;
    if (shape != null)
    {
      // Visibility depends on what is selected.
      command.Visible = true;
      ModelClass element = shape.ModelElement as ModelClass;
      // Enabled depends on state of selection.
      if (element != null && element.Comments.Count == 0)
      {
        command.Enabled = true;
        return; // seen enough
} } } }

以下片段通常是有用的。 OnStatus 方法:

  • this.CurrentSelection.用户右击的形状中始终包含列表。如果用户单击关系图的空白部分,关系图是列表的成员。

  • this.IsDiagramSelected() -true ,如果用户单击关系图的空白部分。

  • this.IsCurrentDiagramEmpty()

  • this.IsSingleSelection() - 用户未选择多个对象

  • this.SingleSelection - 用户右击的形状或关系图

  • shape.ModelElement as MyLanguageElement - 形状表示的模型元素。

一般原则是,使 Visible 属性取决于内容。选择并进行 Enabled 属性取决于所选元素的状态。

OnStatus 方法不应更改存储 " 状态。

Dd820681.collapse_all(zh-cn,VS.110).gif确定命令

对于每个命令,请定义所需执行的操作的一个 OnMenu... 方法,当用户单击菜单命令时。

如果对模型元素的更改,则必须先在事务内。有关更多信息,请参见 如何:使用域特定语言修改标准的菜单命令

在此示例中, ClassShape、 ModelClass和 Comment 是在 DSL 定义,从类图 DSL 模板派生类型。

private void OnMenuMyContextMenuCommand(object sender, EventArgs e)
{
  MenuCommand command = sender as MenuCommand;
  Store store = this.CurrentDocData.Store;
  // Changes to elements and shapes must be performed in a Transaction.
  using (Transaction transaction =
       store.TransactionManager.BeginTransaction("My command"))
  {
    foreach (object selectedObject in this.CurrentSelection)
    {
      // ClassShape is defined in my DSL.
      ClassShape shape = selectedObject as ClassShape;
      if (shape != null)
      {
        // ModelClass is defined in my DSL.
        ModelClass element = shape.ModelElement as ModelClass;
        if (element != null)
        {
          // Do required action here - for example:

          // Create a new element. Comment is defined in my DSL.
          Comment newComment = new Comment(element.Partition);
          // Every element must be the target of an embedding link.
          element.ModelRoot.Comments.Add(newComment);
          // Set properties of new element.
          newComment.Text = "This is a comment";
          // Create a reference link to existing object.
          element.Comments.Add(newComment);
        }
      }
    }
    transaction.Commit(); // Don't forget this!
  }
}

有关如何从对象之间导航的更多信息。对象在设计和有关如何创建对象和链接,请参见 如何:使用域特定语言修改标准的菜单命令

Dd820681.collapse_all(zh-cn,VS.110).gif注册命令

循环访问 C# 在 CommandSet.vsct 的符号部分进行 GUID 和 ID 值的说明:

    private Guid guidCustomMenuCmdSet = 
        new Guid("00000000-0000-0000-0000-000000000000");
    private const int grpidMyMenuGroup = 0x01001;
    private const int cmdidMyContextMenuCommand = 1;

使用 GUID 值与您在 Commands.vsct插入到。

说明说明

如果更改 VSCT 文件中的符号部分,也必须更改这些声明才能匹配。还应递增 Package.tt 的版本号

注册作为此设置命令的一部分的菜单命令。,在关系图的初始化时,GetMenuCommands() 一次调用:

protected override IList<MenuCommand> GetMenuCommands()
{
  // Get the list of generated commands.
  IList<MenuCommand> commands = base.GetMenuCommands();
  // Add a custom command:
  DynamicStatusMenuCommand myContextMenuCommand =
    new DynamicStatusMenuCommand(
      new EventHandler(OnStatusMyContextMenuCommand),
      new EventHandler(OnMenuMyContextMenuCommand),
      new CommandID(guidCustomMenuCmdSet, cmdidMyContextMenuCommand));
  commands.Add(myContextMenuCommand);
  // Add more commands here.
  return commands;
} 

测试命令

生成并运行在 Visual Studio 的实验实例中 DSL。命令应出现在指定的情况的快捷菜单。

执行命令

  1. 解决方案资源管理器 工具栏上,单击 转换所有模板

  2. F5 重新生成解决方案,然后开始调试在实验性生成的域特定语言。

  3. 在实验性生成,请打开示例关系图。

  4. 右击关系图的各个项目验证命令正确地启用或禁用和正确显示或隐藏,具体取决于所选的项目。

疑难解答

命令没有出现在菜单:

  • 该命令将仅显示在 Visual Studio 调试实例中,在中,直到您安装 DSL 包。有关更多信息,请参见 部署域特定语言解决方案

  • 确保该测试示例具有此 DSL 的正确的文件扩展名。若要检查文件扩展名,请在 Visual Studio 中打开主实例中 DslDefinition.dsl。然后在 DSL 资源管理器中,右击编辑节点,然后单击属性。在 " 属性 " 窗口中,检查 FileExtension 属性。

  • 您 增加包版本号?

  • 在 OnStatus 方法的开始处设置断点。,当您右击关系图时,的任何部分它应中断。

    OnStatus 方法未调用:

    • 确保 GUID 和 ID 在 CommandSet 代码与在 Commands.vsct 的符号部分。

    • 在 Commands.vsct,请确保 GUID 和 ID 在每个父节点标识正确的父组。

    • 在 Visual Studio 命令提示符处,键入 devenv /rootsuffix exp /setup。然后重新启动 Visual Studio 调试实例。

  • 通过 OnStatus 方法执行验证该命令。可见和命令。启用设置为 true。

错误的菜单,将显示文本或命令在错误的位置出现:

  • 确保 GUID 和 ID 的组合对于此命令是唯一的。

  • 确保卸载包的早期版本。

请参见

概念

如何:使用域特定语言修改标准的菜单命令

其他资源

编写代码以自定义域特定语言

Sample code: Circuit Diagrams