visual studio插件开发-Menu

工欲善其事,必先利其器,作为程序员我们很大部分时间在和ide打交道,好的插件可以大大提高我们的编程效率,我开发过几个vs插件来解决一键生成dbmodels,快速部署到服务器,总结下来最关键的还是对于Menu这块的扩展,因为这是插件功能的最常见的入口之一,下面给大家介绍vs插件各种menu的扩展

环境准备

这里我使用vs2022版本,要开发vs插件的话,需要vs安装插件开发模块

打开vs 然后点击 工具 -> 获取工具和功能

visual studio插件开发-Menu

然后勾选Visual Studio扩展开发

visual studio插件开发-Menu

小试牛刀

安装好之后,打开vs就可以选择到 vsix project 模板了

visual studio插件开发-Menu

我们利用vsix project模板创建一个插件工程

visual studio插件开发-Menuvisual studio插件开发-Menu
  • MenuDemoVSIXPackage.cs(是插件的入口类)
  • source.extension.vsixmanifest(插件的描述,比如版本,说明等描述性配置的地方)

空的vsix project就创建成功了,我们添加一个command(菜单操作)

visual studio插件开发-Menuvisual studio插件开发-Menu

创建了一个Command会新增下面3个

  • 一个png (图标)
  • 一个vsct (不管几个Command都只会有一个这个文件,包含所有自定义菜单的配置)
  • TestCommand.cs (自定义菜单的命令,点击菜单的执行操作逻辑在里面)

visual studio插件开发-Menu

点击启动这个插件,会打开一个有插件环境的vs(隔离的)

会看到我们的Command名称:Invoke TestCommand按钮在vs的[工具]这个菜单里面, 点击它会出一个弹框,如下

visual studio插件开发-Menu

好了,以上完成初体验后,回到本文要重点介绍:vs的Menu扩展

vs的Menu扩展

上面我们说到 vsct文件,我们的按钮是展示在Vs哪种类型的Menu下,就是在这个文件定义的,我们一起看下这个vsct文件,关键部分我都用不同颜色来高亮显示

visual studio插件开发-Menu
CommandTable 表示与VSPackage关联的所有命令、菜单组和菜单。
Extern 表示引用外部.h文件,最终会与.vsct文件合并的
  • stdidcmd.h
  • vsshlids.h

VSCT 编译器能使用 C++ 宏和预处理,通过extern引入头文件,比如vsshlids.h vsshlids.h 头文件位于

{VS安装目录}\VSSDK\VisualStudioIntegration\Common\Inc,

例如我的目录是

C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VSSDK\VisualStudioIntegration\Common\Inc

vsct 文件中有用到宏 IDM_VS_MENU_TOOLS = 0x0005,

它表示 VS 上的 Tools 菜单的ID,这个宏即位于 vsshlids.h 头文件中。

如果不引入这个头文件,那么就得写0x0005,导致可读性很差和难维护!

visual studio插件开发-Menu
Commands 表示可以执行命令的集合。每个命令都有以下四个子元素:
  • Menus 是菜单/工具栏的集合。菜单是Commands的容器。
  • Groups 决定菜单的位置
  • Buttons 表示命令按钮/菜单项
  • Bitmaps 按钮/菜单项的图标配置
CommandPlacements 指示各个命令应位于VSPackage菜单中的其他位置。
Symbols 包含包中所有命令的符号名和GUID, ID。
KeyBindings 快捷键指定 例如Ctrl+S。

以上vsct的xml scheme 的详细说明在这里有文档

https://github.com/MicrosoftDocs/visualstudio-docs/blob/main/docs/extensibility/internals/designing-xml-command-table-dot-vsct-files.md

一级菜单

<groups>
&#xA0;&#xA0;<group guid="guidmenudemovsixpackagecmdset" id="mymenugroup" priority="0x0600">
&#xA0;&#xA0;&#xA0;&#xA0;<!-- 这个guid和id决定了菜单的位置 -->
&#xA0;&#xA0;&#xA0;&#xA0;<parent guid="guidshlmainmenu" id="idm_vs_menu_tools">
&#xA0;&#xA0;
</parent guid="guidshlmainmenu" id="idm_vs_menu_tools"></group guid="guidmenudemovsixpackagecmdset" id="mymenugroup" priority="0x0600"></groups>

如果想要展示在vs的下面这些菜单里面,直接可以用上面的方式 修改id就可以了

visual studio插件开发-Menu

id的定义都在vsshlids.h 头文件,常用的如下

-&#x300B;vs&#x7684;&#x6700;&#x4E0A;&#x9762;&#x4E00;&#x6392;&#x83DC;&#x5355;
#define&#xA0;IDM_VS_MENU_FILE&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0080
#define&#xA0;IDM_VS_MENU_EDIT&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0081
#define&#xA0;IDM_VS_MENU_VIEW&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0082
#define&#xA0;IDM_VS_MENU_PROJECT&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0083
#define&#xA0;IDM_VS_MENU_TOOLS&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0085
#define&#xA0;IDM_VS_MENU_WINDOW&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0086
#define&#xA0;IDM_VS_MENU_ADDINS&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0087
#define&#xA0;IDM_VS_MENU_HELP&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0088
#define&#xA0;IDM_VS_MENU_DEBUG&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0089
#define&#xA0;IDM_VS_MENU_FORMAT&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x008A
#define&#xA0;IDM_VS_MENU_ALLMACROS&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x008B
#define&#xA0;IDM_VS_MENU_BUILD&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x008C
#define&#xA0;IDM_VS_MENU_CONTEXTMENUS&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x008D
#define&#xA0;IDG_VS_MENU_CONTEXTMENUS&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x008E
#define&#xA0;IDM_VS_MENU_REFACTORING&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x008f
#define&#xA0;IDM_VS_MENU_COMMUNITY&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0090
#define&#xA0;IDM_VS_MENU_EXTENSIONS&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0091
-&#x300B;&#xA0;&#x5DE5;&#x7A0B;&#x6587;&#x4EF6;&#x53F3;&#x952E;&#x83DC;&#x5355;&#xA0;&#x5BF9;&#x5E94;&#x4E0A;&#x56FE;&#x7684;13
#define&#xA0;IDM_VS_CTXT_PROJNODE&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0402
-&#x300B;&#x4EE3;&#x7801;&#x7A97;&#x53E3;&#x7684;&#x53F3;&#x952E;&#x83DC;&#x5355;&#x64CD;&#x4F5C;&#xA0;&#x5BF9;&#x5E94;&#x4E0A;&#x56FE;&#x7684;14
#define&#xA0;IDM_VS_CTXT_CODEWIN&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x040D
-&#x300B;&#x89E3;&#x51B3;&#x65B9;&#x6848;&#x7684;&#x53F3;&#x952E;&#x83DC;&#x5355;&#x64CD;&#x4F5C;&#xA0;&#x5BF9;&#x5E94;&#x4E0A;&#x56FE;&#x7684;15
#define&#xA0;IDM_VS_CTXT_SOLNNODE&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0413
-&#x300B;&#xA0;&#x67D0;&#x4E2A;&#x6587;&#x4EF6;&#x7684;&#x53F3;&#x952E;&#x83DC;&#x5355;&#xA0;&#x8FD9;&#x4E2A;&#x4E5F;&#x7ECF;&#x5E38;&#x7528;
#define&#xA0;IDM_VS_CTXT_ITEMNODE&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0x0430

各个含义说明也可以参考文档

https://learn.microsoft.com/en-us/visualstudio/extensibility/internals/guids-and-ids-of-visual-studio-menus?view=vs-2022

比如我把上面的demo改成这样

<groups>
&#xA0;&#xA0;<group guid="guidmenudemovsixpackagecmdset" id="mymenugroup" priority="0x0600">
&#xA0;&#xA0;&#xA0;&#xA0;<!-- 工程文件右键菜单 -->
&#xA0;&#xA0;&#xA0;&#xA0;<parent guid="guidshlmainmenu" id="idm_vs_ctxt_projnode">
&#xA0;&#xA0;
</parent guid="guidshlmainmenu" id="idm_vs_ctxt_projnode"></group guid="guidmenudemovsixpackagecmdset" id="mymenugroup" priority="0x0600"></groups>

visual studio插件开发-Menu

改成这样就会显示在代码窗口的右键菜单中

<groups>
&#xA0;&#xA0;<group guid="guidmenudemovsixpackagecmdset" id="mymenugroup" priority="0x0600">
&#xA0;&#xA0;&#xA0;&#xA0;<!-- 代码窗口的右键菜单操作 -->
&#xA0;&#xA0;&#xA0;&#xA0;<parent guid="guidshlmainmenu" id="idm_vs_ctxt_codewin">
&#xA0;&#xA0;
</parent guid="guidshlmainmenu" id="idm_vs_ctxt_codewin"></group guid="guidmenudemovsixpackagecmdset" id="mymenugroup" priority="0x0600"></groups>

visual studio插件开发-Menu

所以一级菜单只需要添加一个Group 并且设置该Group的Parent为已知的定义ID即可

二级菜单

这里需要添加Menu了 且 一级菜单项要定义为Menu而不是Button!!

先新建一个group1以右键菜单为parent(已知定义ID),以group1为parent,再定义一个group2以一级菜单Menu为parent,再将二级菜单项定义为Button并以group2为parent

有点绕吧,比如我要在工程文件的右键菜单 添加一个二级菜单,像下面这样子

visual studio插件开发-Menu
  1. 在Groups节点下新建一个group:MyMenuGroup1 以工程右键菜单为parent
<group guid="guidmenudemovsixpackagecmdset" id="mymenugroup1" priority="0x0600">
&#xA0;&#xA0;&#xA0;&#xA0;<!--定义在头文件的已知定义ID -->
&#xA0;&#xA0;&#xA0;&#xA0;<parent guid="guidshlmainmenu" id="idm_vs_ctxt_projnode">
</parent guid="guidshlmainmenu" id="idm_vs_ctxt_projnode"></group guid="guidmenudemovsixpackagecmdset" id="mymenugroup1" priority="0x0600">
  1. 在Menus节点下新建一个menu:MyMenu,以上面的MyMenuGroup1位parent

<menus>
&#xA0;&#xA0;<menu guid ="guidmenudemovsixpackagecmdset" id="mymenu" priority="0x3110" type="menu">
&#xA0;&#xA0;&#xA0;&#xA0;<parent guid="guidmenudemovsixpackagecmdset" id="mymenugroup1">
&#xA0;&#xA0;&#xA0;&#xA0;<strings>
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<buttontext>New</buttontext>
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<commandname>New</commandname>
&#xA0;&#xA0;&#xA0;&#xA0;</strings>
&#xA0;&#xA0;
</parent guid="guidmenudemovsixpackagecmdset" id="mymenugroup1"></menu guid ="guidmenudemovsixpackagecmdset" id="mymenu" priority="0x3110" type="menu"></menus>
  1. 再创建一个group:MyMenuGroup2 以上面的MyMenu为parent
<group guid="guidmenudemovsixpackagecmdset" id="mymenugroup2" priority="0x0600">
&#xA0;&#xA0;&#xA0;&#xA0;<parent guid="guidmenudemovsixpackagecmdset" id="mymenu">
</parent guid="guidmenudemovsixpackagecmdset" id="mymenu"></group guid="guidmenudemovsixpackagecmdset" id="mymenugroup2" priority="0x0600">
  1. 创建Button以MyMenuGroup2为parent
<buttons>
&#xA0;&#xA0;<button guid="guidmenudemovsixpackagecmdset" id="testcommandid" priority="0x0100" type="button">
&#xA0;&#xA0;&#xA0;&#xA0;<parent guid="guidmenudemovsixpackagecmdset" id="mymenugroup2" >
&#xA0;&#xA0;&#xA0;&#xA0;<icon guid="guidimages" id="bmppic1" >
&#xA0;&#xA0;&#xA0;&#xA0;<strings>
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<buttontext>Invoke&#xA0;TestCommand</buttontext>
&#xA0;&#xA0;&#xA0;&#xA0;</strings>
&#xA0;&#xA0;
</icon guid="guidimages" id="bmppic1" ></parent guid="guidmenudemovsixpackagecmdset" id="mymenugroup2" ></button guid="guidmenudemovsixpackagecmdset" id="testcommandid" priority="0x0100" type="button"></buttons>

完整定义:

visual studio插件开发-Menu

如果想要同时显示在多个地方咋整

比如 我既要显示在工程右键菜单里面,又要显示在普通文件的右键菜单,又要显示在代码右键菜单

这里就用到上面提到的 CommandPlacements

还是以上面的例子,这时候第一步的group1:MyMenuGroup2的parent就不能填了

而是要添加CommandPlacements ,id要填 MyMenuGroup2 ,Parent填具体ID

<commandplacements>
&#xA0;&#xA0;&#xA0;&#xA0;<commandplacement guid="guidmenudemovsixpackagecmdset" id="mymenugroup1" priority="0x0000">
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<parent guid="guidshlmainmenu" id="idm_vs_ctxt_projnode">
&#xA0;&#xA0;&#xA0;&#xA0;
&#xA0;&#xA0;&#xA0;&#xA0;<commandplacement guid="guidmenudemovsixpackagecmdset" id="mymenugroup1" priority="0x0000">
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<parent guid="guidshlmainmenu" id="idm_vs_ctxt_itemnode" >
&#xA0;&#xA0;&#xA0;&#xA0;
&#xA0;&#xA0;&#xA0;&#xA0;<commandplacement guid="guidmenudemovsixpackagecmdset" id="mymenugroup1" priority="0x0000">
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<parent guid="guidshlmainmenu" id="idm_vs_ctxt_codewin" >
&#xA0;&#xA0;&#xA0;&#xA0;
</parent guid="guidshlmainmenu" id="idm_vs_ctxt_codewin" ></commandplacement guid="guidmenudemovsixpackagecmdset" id="mymenugroup1" priority="0x0000"></parent guid="guidshlmainmenu" id="idm_vs_ctxt_itemnode" ></commandplacement guid="guidmenudemovsixpackagecmdset" id="mymenugroup1" priority="0x0000"></parent guid="guidshlmainmenu" id="idm_vs_ctxt_projnode"></commandplacement guid="guidmenudemovsixpackagecmdset" id="mymenugroup1" priority="0x0000"></commandplacements>

visual studio插件开发-Menu

效果如下:

visual studio插件开发-Menu

怎样动态展示菜单

比如 ,非json文件的就不展示

visual studio插件开发-Menu

是json文件的才展示

visual studio插件开发-Menu

在Button的增加 DynamicVisibility


&#xA0;<button guid="guidmenudemovsixpackagecmdset" id="testcommandid" priority="0x0100" type="button">
&#xA0;&#xA0;&#xA0;&#xA0;<parent guid="guidmenudemovsixpackagecmdset" id="mymenugroup2" >
&#xA0;&#xA0;&#xA0;&#xA0;<!--这个 -->
&#xA0;&#xA0;&#xA0;&#xA0;<commandflag>DynamicVisibility</commandflag>
&#xA0;&#xA0;&#xA0;&#xA0;<icon guid="guidimages" id="bmppic1" >
&#xA0;&#xA0;&#xA0;&#xA0;<strings>
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<buttontext>Invoke&#xA0;TestCommand</buttontext>
&#xA0;&#xA0;&#xA0;&#xA0;</strings>
</icon guid="guidimages" id="bmppic1" ></parent guid="guidmenudemovsixpackagecmdset" id="mymenugroup2" ></button guid="guidmenudemovsixpackagecmdset" id="testcommandid" priority="0x0100" type="button">

让VsPackage随着项目启动后就立即加载,不然动态判断逻辑无法提前指定

visual studio插件开发-Menu

修改Command的初始化方法,拿到DTE,很多功能点需要用到它里面的接口,比如拿到当前选择的item

visual studio插件开发-Menu

然后再初始化Menu的时候指定BeforeQueryStatus的逻辑为后缀为json才展示

visual studio插件开发-Menu

总结

我觉得对于visual studio中如何用插件来扩展menu 大概了解上面几点就差不多了,希望能帮助到你

有个好消息和大家分享,昨天收到通知我当选了本届的微软MVP,以后会带给大家更多的技术分享~~~

Enjoy!!!

关注公众号一起学习

visual studio插件开发-Menu

Original: https://www.cnblogs.com/yudongdong/p/16837986.html
Author: 俞正东
Title: visual studio插件开发-Menu

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/799906/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球