You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Visual Studio扩展:调用选项窗口及测试菜单ID问题咨询

刚好我之前开发VS扩展时也碰到过这两个问题,给你整理下解决方案:

1. 找到Test菜单的ID并修改菜单归属

VS内置的Test菜单对应的ID是 IDM_VS_MENU_TEST,你可以直接在.vsct文件中用这个ID作为父容器来调整菜单命令的归属。

举个配置例子:如果要把自定义菜单命令放到Test菜单下,在<Groups>节点定义你的组时,指定parent为这个ID即可:

<Groups>
  <Group guid="guidYourExtensionCmdSet" id="MyTestMenuGroup" priority="0x0600">
    <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TEST" />
  </Group>
</Groups>

如果是要直接添加子菜单到Test菜单下,在<Menus>节点这样配置:

<Menus>
  <Menu guid="guidYourExtensionCmdSet" id="MyCustomTestMenu" priority="0x0600" type="Menu">
    <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TEST" />
    <Strings>
      <ButtonText>My Test Tools</ButtonText>
    </Strings>
  </Menu>
</Menus>

注:guidSHLMainMenu是VS内置主菜单的GUID,一般你的vsct文件已经通过<Extern>引用了对应的头文件(比如VSStd97.h),可以直接使用这些常量。

2. 在Tools > My Menus下添加Options命令跳转自定义配置页

要实现点击命令直接打开你的选项配置页,分两步操作:

第一步:在.vsct里定义命令并归属到目标位置

假设你已经创建了My Menus组,在<Buttons>节点添加你的Options命令:

<Buttons>
  <Button guid="guidYourExtensionCmdSet" id="OptionsCmdId" priority="0x0100" type="Button">
    <Parent guid="guidYourExtensionCmdSet" id="MyMenusGroup" /> <!-- 替换成你的My Menus组ID -->
    <Icon guid="guidImages" id="bmpPic1" />
    <Strings>
      <ButtonText>Options</ButtonText>
    </Strings>
  </Button>
</Buttons>

第二步:在命令回调中打开指定选项页

在你的命令类的Execute方法里,通过VS的IVsUIShellOpenDialog服务直接定位到你的配置页,代码示例如下:

using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System;
using System.ComponentModel.Design;
using System.Threading.Tasks;

public sealed class OptionsCommand
{
    private readonly AsyncPackage package;
    public const int CommandId = 0x0100;
    public static readonly Guid CommandSet = new Guid("YOUR_COMMAND_SET_GUID");

    private OptionsCommand(AsyncPackage package, OleMenuCommandService commandService)
    {
        this.package = package ?? throw new ArgumentNullException(nameof(package));
        commandService = commandService ?? throw new ArgumentNullException(nameof(commandService));

        var menuCommandID = new CommandID(CommandSet, CommandId);
        var menuItem = new MenuCommand(this.Execute, menuCommandID);
        commandService.AddCommand(menuItem);
    }

    public static OptionsCommand Instance { get; private set; }

    public AsyncPackage Package => this.package;

    public static async Task InitializeAsync(AsyncPackage package)
    {
        await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
        var commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
        Instance = new OptionsCommand(package, commandService);
    }

    private async void Execute(object sender, EventArgs e)
    {
        await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
        
        // 获取VS的对话框服务
        var uiShellOpenDialog = await package.GetServiceAsync(typeof(SVsUIShellOpenDialog)) as IVsUIShellOpenDialog;
        if (uiShellOpenDialog != null)
        {
            // 替换成你的选项页类上[Guid("...")]属性中的值
            Guid optionsPageGuid = new Guid("YOUR_OPTION_PAGE_GUID");
            // 打开选项窗口并直接定位到你的配置页
            uiShellOpenDialog.OpenOptionsDialog(0, ref optionsPageGuid);
        }
    }
}

记得替换代码里的两个GUID:

  • YOUR_COMMAND_SET_GUID:你的扩展命令集的GUID,在vsct文件的<GuidSymbol>节点中定义
  • YOUR_OPTION_PAGE_GUID:你的自定义选项页类(继承自DialogPage)上[Guid]属性的字符串值

另外,要确保你的选项页已经在Package类中通过ProvideOptionPageAttribute注册,比如:

[ProvideOptionPage(typeof(MyOptionsPage), "My Extension", "General", 0, 0, true)]
public sealed class YourExtensionPackage : AsyncPackage
{
    // Package初始化逻辑...
}

内容的提问来源于stack exchange,提问作者Icaroto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:28:45