将最近使用的列表添加到子菜单

本演练基于“向菜单添加子菜单”中的演示,并演示如何向子菜单添加动态列表。 动态列表构成了创建最近使用的最新列表的基础。

动态菜单列表以菜单上的占位符开头。 每次显示菜单时,Visual Studio 集成开发环境(IDE)都会向 VSPackage 询问应在占位符处显示的所有命令。 动态列表可以在菜单上的任意位置发生。 但是,动态列表通常由子菜单或菜单底部自行存储和显示。 使用这些设计模式,可以启用命令的动态列表以展开和收缩,而不会影响菜单上其他命令的位置。 在本演练中,动态 MRU 列表显示在现有子菜单的底部,以一行分隔与子菜单的其余部分。

从技术上看,动态列表也可以应用于工具栏。 但是,我们不建议使用,因为工具栏应该保持不变,除非用户采取特定步骤来更改它。

本演练创建一个 MRU 列表,其中包含四个项,每次选择其中一个项目时更改其顺序(所选项移动到列表顶部)。

有关菜单和 .vsct 文件的详细信息,请参阅 命令、菜单和工具栏

先决条件

要按照本演练的步骤操作,必须安装 Visual Studio SDK。 有关详细信息,请参阅 Visual Studio SDK

创建扩展

  • 按照“将子菜单添加到菜单”中的过程创建以下过程中修改的子菜单。

    本演练中的过程假定 VSPackage TestCommand的名称是,这是将菜单添加到 Visual Studio 菜单栏中的名称

创建动态项列表命令

  1. 打开 TestCommandPackage.vsct

  2. Symbols节中GuidSymbol,在名为 guidTestCommandPackageCmdSet 的节点中,添加组和cmdidMRUList命令的MRUListGroup符号,如下所示。

    <IDSymbol name="MRUListGroup" value="0x1200"/>
    <IDSymbol name="cmdidMRUList" value="0x0200"/>
    
  3. 在该 Groups 部分中,在现有组条目之后添加声明的组。

    <Group guid="guidTestCommandPackageCmdSet" id="MRUListGroup"
            priority="0x0100">
        <Parent guid="guidTestCommandPackageCmdSet" id="SubMenu"/>
    </Group>
    
  4. 在该 Buttons 部分中,添加一个节点来表示新声明的命令,该命令位于现有按钮条目之后。

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

    DynamicItemStart 标志允许动态生成命令。

  5. 生成项目并开始调试以测试新命令的显示。

    TestMenu 菜单上,单击新的子菜单“ 子菜单”以显示新命令 MRU 占位符。 在下一过程中实现命令的动态 MRU 列表后,每次打开子菜单时,该命令标签都将替换为该列表。

填写 MRU 列表

  1. TestCommandPackageGuids.cs 中,在类定义中的 TestCommandPackageGuids 现有命令 ID 后面添加以下行。

    public const string guidTestCommandPackageCmdSet = "00000000-0000-0000-0000-00000000"; // get the GUID from the .vsct file
    public const uint cmdidMRUList = 0x200;
    
  2. TestCommand.cs 中添加以下 using 语句。

    using System.Collections;
    
  3. 在最后一个 AddCommand 调用之后,在 TestCommand 构造函数中添加以下代码。 InitMRUMenu稍后将定义

    this.InitMRUMenu(commandService);
    
  4. 在 TestCommand 类中添加以下代码。 此代码初始化表示要显示在 MRU 列表上的项的字符串列表。

    private int numMRUItems = 4;
    private int baseMRUID = (int)TestCommandPackageGuids.cmdidMRUList;
    private ArrayList mruList;
    
    private void InitializeMRUList()
    {
        if (null == this.mruList)
        {
            this.mruList = new ArrayList();
            if (null != this.mruList)
            {
                for (int i = 0; i < this.numMRUItems; i++)
                {
                    this.mruList.Add(string.Format(CultureInfo.CurrentCulture,
                        "Item {0}", i + 1));
                }
            }
        }
    }
    
  5. InitializeMRUList 方法之后,添加该方法 InitMRUMenu 。 这会初始化 MRU 列表菜单命令。

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

    必须为 MRU 列表中每个可能的项创建菜单命令对象。 IDE 将调用 OnMRUQueryStatus MRU 列表中每个项的方法,直到没有其他项。 在托管代码中,IDE 知道没有更多项的唯一方法是首先创建所有可能的项。 如果需要,可以在创建菜单命令后先将 mc.Visible = false; 其他项标记为不可见。 然后,可以通过在方法中使用mc.Visible = true;OnMRUQueryStatus这些项来显示这些项。

  6. 方法 InitMRUMenu 后,添加以下 OnMRUQueryStatus 方法。 这是设置每个 MRU 项的文本的处理程序。

    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;
            }
        }
    }
    
  7. 方法 OnMRUQueryStatus 后,添加以下 OnMRUExec 方法。 这是用于选择 MRU 项的处理程序。 此方法将所选项移动到列表顶部,然后在消息框中显示所选项。

    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));
            }
        }
    }
    

测试 MRU 列表

  1. 生成项目并启动调试。

  2. 在 TestMenu 菜单上,单击“调用 TestCommand”。 执行此操作会显示一个消息框,指示已选择该命令。

    注意

    此步骤需要强制 VSPackage 加载并正确显示 MRU 列表。 如果跳过此步骤,则不显示 MRU 列表。

  3. “测试菜单” 菜单上,单击“ 子菜单”。 子菜单末尾显示在分隔符下方的四个项目的列表。 单击 “项目 3”时,应显示一个消息框,并显示文本“ 所选项目 3”。 (如果未显示四个项目的列表,请确保已按照前面的步骤中的说明进行操作。

  4. 再次打开子菜单。 请注意, 项目 3 现在位于列表顶部,其他项已向下推送到一个位置。 再次单击 “项目 3 ”,并注意到消息框仍显示 “选定项 3”,这表示文本已正确移动到新位置以及命令标签。