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
相关产品推荐
相关产品推荐

