如何:请动态添加菜单项

在基于 XML 的命令表配置的命令 (.vsct) 文件中定义的 DynamicItemStart 标志以指定在插入动态创建的命令的菜单中的位置。 动态命令通常创建,在关联的 VSPackage 启动时可以更新,在 VSPackage 处于打开状态时。

两个常见动态列表如下所示:

  • 最近使用 (MRU)过列表,通常显示名称的文档最近打开的。

  • 窗口列出,通常显示窗口的名称现在打开。

在命令定义的 DynamicItemStart 标志以指定命令只是占位符,直到打开 VSPackage。 打开后 VSPackage,占位符以创建在运行时由 VSPackage 并将其添加到动态的 0 个或多个命令替换列表。 您可能无法发现在动态列表的菜单的位置出现,直到打开 VSPackage。

若要填充动态列表,集成开发环境 (IDE) (ide) 第一次调用 VSPackage 查找具有 ID 第一个字符是否与占位符的 ID 的命令。 当 IDE 查找匹配的命令时,它将命令的名称到动态列表。 然后 IDE 增加 ID 并查找另一个匹配的命令添加到动态列表。 IDE 继续增加 ID,并将添加到动态列表,它就动态命令。

第一个过程在子菜单描述如何创建动态 MRU 列表。

使用托管包结构,第二个过程描述如何填写动态列表 (MPF)。

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

有关如何创建 MRU 列表的信息,请参见 演练:添加最近使用过的列表添加到子菜单

创建动态命令列出

若要创建动态命令列出,必须先添加到 .vsct 文件的一个 按钮 元素。 此元素变为列表的占位符在 IDE。 然后用代码来实现列表。

若要创建动态的占位符命令列出

  1. 在 .vsct 文件,请创建一个包含命令组的子菜单。 有关更多信息,请参见 如何:创建菜单上子菜单和快捷菜单

    此子菜单将包含动态列表。

  2. 在 .vsct 文件的 Symbols 部分,定位到包含其他命令的 GuidSymbol 元素。 添加 MRUListGroup 组的一个 IDSymbol 元素,并动态的 cmdidMRUList 命令列表占位符,如下所示。

  3. 定义一组,如下所示。

    <Group guid="guidTopLevelMenuCmdSet" id="MRUListGroup" priority="0x100">
      <Parent guid="guidTopLevelMenuCmdSet" id="SubMenu"/>
    </Group>
    
  4. 定义新的命令为 Buttons 的一部分 Button 元素。

    1. 设置 guid ,并 id 字段设置为 GUID: 表示新元素的 ID 匹配。 GUID: ID 对由 GuidSymbol 和 IDSymbol 元素的 name 值从在上一步中。

      此 GUID: ID 匹配是第一个在运行时添加由 VSPackage 动态命令的列表。 每个后续动态命令具有与上述动态命令的 ID 是一个大的 ID。

    2. 设置 type 属性设置为 按钮。

      动态命令具有与任何其他命令的类型按钮。

    3. 不要将该命令的一 priority 属性。

      此子菜单仅包含一个动态列表。 因此,第一项的优先级不重要。 以后添加的动态项目具有相同优先级;每个添加的顺序指定其相对位置。

    4. 添加具有 guid 和 id 属性与这些组为子菜单创建一个 元素。

    5. 添加一个 命令标志 元素并将其值设置为 DynamicItemStart。

      这指示命令作为占位符。

      备注

      其他标志被忽略。如果要控制动态项目的可见性,必须从 VSPackage 这样做在运行时。

    6. 添加包含一个 ButtonText 元素和一个 CommandName 元素并将其值设置为占位符的名称为 字符串 元素。

      通常,此按钮文本中未看到 VSPackage 是否能初始化动态列表,在包含之前的菜单显示。

    7. 不要指定 图标 元素。

      动态命令不能具有与其关联的图标。

    下面的示例演示 MRU 的完整命令定义列表占位符。

    <Button guid="guidTopLevelMenuCmdSet" id="cmdidMRUList"
            type="Button" priority="0x0100">
      <Parent guid="guidTopLevelMenuCmdSet" id="MRUListGroup" />
      <CommandFlag>DynamicItemStart</CommandFlag>
      <Strings>
        <CommandName>cmdidMRUList</CommandName>
        <ButtonText>MRU Placeholder</ButtonText>
      </Strings>
    </Button>
    

实现动态列表

托管包框架 (MPF)使用事件处理程序中隐藏 IOleCommandTarget 接口及其 QueryStatus 方法的详细信息。 对于编写使用 MPF 支持动态的 VSPackage 列表菜单命令,生成 OleMenuCommand 对象列表,其中每个代表在动态的项列表。 每 OleMenuCommand 对象具有执行的命令相同的事件处理程序和获取的命令的状态同一个事件处理程序。

备注

从声明方式的 演练:添加最近使用过的列表添加到子菜单 的以下过程使用代码实现动态列表。但是,代码不创建完全 VSPackage。有关完整示例,请参见演练。

若要实现动态列表

  1. 添加 ID 到 ID 列表。 PkgCmdID.cs 的。

    public const uint cmdidMRUList = 0x200;
    
  2. 使用语句,在 TopLevelMenuPackage.cs 添加此操作。

    using System.Collections;
    
  3. 将占位符。 OleMenuCommand 实例并为其分配事件处理程序。 下面的示例中的方法以包的 Initialize() 方法调用。

    private void InitMRUMenu(OleMenuCommandService mcs)
    {
        InitializeMRUList();
        for (int i = 0; i < this.numMRUItems; i++)
        {
            var cmdID = new CommandID(
                GuidList.guidTopLevelMenuCmdSet, this.baseMRUID + i);
            var mc = new OleMenuCommand(
                new EventHandler(OnMRUExec), cmdID);
            mc.BeforeQueryStatus += new EventHandler(OnMRUQueryStatus);
            mcs.AddCommand(mc);
        }
    }
    

    此过程中的示例假定,使用以下私有变量。

    private int numMRUItems = 4;
    private int baseMRUID = (int)PkgCmdIDList.cmdidMRUList;
    private ArrayList mruList;
    
  4. 如下面的示例所示,使用 QueryStatus 事件处理程序填充动态列表,。

    private void OnMRUQueryStatus(object sender, EventArgs e)
    {
        OleMenuCommand menuCommand = sender as OleMenuCommand;
        if (null != menuCommand)
        {
            int MRUItemIndex = menuCommand.CommandID.ID - this.baseMRUID;
            if (MRUItemIndex >= 0 && MRUItemIndex < this.mruList.Count)
            {
                menuCommand.Text = this.mruList[MRUItemIndex] as string;
            }
        }
    }
    
  5. ,在列表中的项单击,则实现 exec 处理程序以响应。 下面的示例更新位置列表项,以便最近出现一个顶部。

    private void OnMRUExec(object sender, EventArgs e)
    {
        var menuCommand = sender as OleMenuCommand;
        if (null != menuCommand)
        {
            int MRUItemIndex = menuCommand.CommandID.ID - this.baseMRUID;
            if (MRUItemIndex >= 0 && MRUItemIndex < this.mruList.Count)
            {
                string selection = this.mruList[MRUItemIndex] as string;
                for (int i = MRUItemIndex; i > 0; i--)
                {
                    this.mruList[i] = this.mruList[i - 1];
                }
                this.mruList[0] = selection;
                System.Windows.Forms.MessageBox.Show(
                    string.Format(CultureInfo.CurrentCulture,
                                  "Selected {0}", selection));
            }
        }
    }
    

    您也可以使用 Text 属性或 CommandID 特性标识选定了哪个项并相应地响应。

  6. 通过设置 Visible 属性控制菜单或单个菜单项的可见性。 下面的代码使不可见的菜单或的菜单项。

    var menuCommand = sender as OleMenuCommand;
    menuCommand.Visible = false;
    

    ,因为它提供 sender 参数到该处理程序,将上面的代码在 QueryStatus 处理程序将它应用于整个菜单。 但是,置于 exec 处理程序会影响执行的单个菜单项。

请参见

概念

Vspackage 如何将用户界面元素到 IDE

其他资源

命令、菜单和工具栏

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