工欲善其事,必先利其器,作为程序员我们很大部分时间在和ide打交道,好的插件可以大大提高我们的编程效率,我开发过几个vs插件来解决一键生成dbmodels,快速部署到服务器,总结下来最关键的还是对于Menu这块的扩展,因为这是插件功能的最常见的入口之一,下面给大家介绍vs插件各种menu的扩展
这里我使用vs2022版本,要开发vs插件的话,需要vs安装插件开发模块
打开vs 然后点击 工具 -> 获取工具和功能
然后勾选Visual Studio扩展开发
安装好之后,打开vs就可以选择到 vsix project 模板了
image
我们利用vsix project模板创建一个插件工程
image
image
MenuDemoVSIXPackage.cs(是插件的入口类)
source.extension.vsixmanifest(插件的描述,比如版本,说明等描述性配置的地方)
空的vsix project就创建成功了,我们添加一个command(菜单操作)
image
image
创建了一个Command会新增下面3个
一个png (图标)
一个vsct (不管几个Command都只会有一个这个文件,包含所有自定义菜单的配置)
TestCommand.cs (自定义菜单的命令,点击菜单的执行操作逻辑在里面)
image
点击启动这个插件,会打开一个有插件环境的vs(隔离的)
会看到我们的Command名称:Invoke TestCommand按钮在vs的[工具]这个菜单里面, 点击它会出一个弹框,如下
好了,以上完成初体验后,回到本文要重点介绍:vs的Menu扩展
上面我们说到 vsct文件,我们的按钮是展示在Vs哪种类型的Menu下,就是在这个文件定义的,我们一起看下这个vsct文件,关键部分我都用不同颜色来高亮显示
image
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,导致可读性很差和难维护!
image
Menus 是菜单/工具栏的集合。菜单是Commands的容器。
Groups 决定菜单的位置
Buttons 表示命令按钮/菜单项
Bitmaps 按钮/菜单项的图标配置
<Groups>
<Group guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup" priority="0x0600">
<!-- 这个guid和id决定了菜单的位置 -->
<Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
</Group>
</Groups>
如果想要展示在vs的下面这些菜单里面,直接可以用上面的方式 修改id就可以了
image
id的定义都在vsshlids.h 头文件,常用的如下
-》vs的最上面一排菜单
#define IDM_VS_MENU_FILE 0x0080
#define IDM_VS_MENU_EDIT 0x0081
#define IDM_VS_MENU_VIEW 0x0082
#define IDM_VS_MENU_PROJECT 0x0083
#define IDM_VS_MENU_TOOLS 0x0085
#define IDM_VS_MENU_WINDOW 0x0086
#define IDM_VS_MENU_ADDINS 0x0087
#define IDM_VS_MENU_HELP 0x0088
#define IDM_VS_MENU_DEBUG 0x0089
#define IDM_VS_MENU_FORMAT 0x008A
#define IDM_VS_MENU_ALLMACROS 0x008B
#define IDM_VS_MENU_BUILD 0x008C
#define IDM_VS_MENU_CONTEXTMENUS 0x008D
#define IDG_VS_MENU_CONTEXTMENUS 0x008E
#define IDM_VS_MENU_REFACTORING 0x008f
#define IDM_VS_MENU_COMMUNITY 0x0090
#define IDM_VS_MENU_EXTENSIONS 0x0091
-》 工程文件右键菜单 对应上图的13
#define IDM_VS_CTXT_PROJNODE 0x0402
-》代码窗口的右键菜单操作 对应上图的14
#define IDM_VS_CTXT_CODEWIN 0x040D
-》解决方案的右键菜单操作 对应上图的15
#define IDM_VS_CTXT_SOLNNODE 0x0413
-》 某个文件的右键菜单 这个也经常用
#define IDM_VS_CTXT_ITEMNODE 0x0430
比如我把上面的demo改成这样
<Groups>
<Group guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup" priority="0x0600">
<!-- 工程文件右键菜单 -->
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_PROJNODE"/>
</Group>
</Groups>
image
改成这样就会显示在代码窗口的右键菜单中
<Groups>
<Group guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup" priority="0x0600">
<!-- 代码窗口的右键菜单操作 -->
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN"/>
</Group>
</Groups>
image
所以一级菜单只需要添加一个Group 并且设置该Group的Parent为已知的定义ID即可
这里需要添加Menu了 且 一级菜单项要定义为Menu而不是Button!!
先新建一个group1以**右键菜单为parent(已知定义ID)**,以group1为parent,再定义一个group2以一级菜单Menu为parent,再将二级菜单项定义为Button并以group2为parent
有点绕吧,比如我要在工程文件的右键菜单 添加一个二级菜单,像下面这样子
image
在Groups节点下新建一个group:MyMenuGroup1 以工程右键菜单为parent
在Menus节点下新建一个menu:MyMenu,以上面的MyMenuGroup1位parent
再创建一个group:MyMenuGroup2 以上面的MyMenu为parent
创建Button以MyMenuGroup2为parent
完整定义:
比如 我既要显示在工程右键菜单里面,又要显示在普通文件的右键菜单,又要显示在代码右键菜单
这里就用到上面提到的 CommandPlacements
还是以上面的例子,这时候第一步的group1:MyMenuGroup2的parent就不能填了
而是要添加CommandPlacements ,id要填 MyMenuGroup2 ,Parent填具体ID
<CommandPlacements>
<CommandPlacement guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup1" priority="0x0000">
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_PROJNODE"/>
</CommandPlacement>
<CommandPlacement guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup1" priority="0x0000">
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_ITEMNODE" />
</CommandPlacement>
<CommandPlacement guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup1" priority="0x0000">
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN" />
</CommandPlacement>
</CommandPlacements>
image
效果如下:
image
比如 ,非json文件的就不展示
是json文件的才展示
在Button的增加 DynamicVisibility
<Button guid="guidMenuDemoVSIXPackageCmdSet" id="TestCommandId" priority="0x0100" type="Button">
<Parent guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup2" />
<!--这个 -->
<CommandFlag>DynamicVisibility</CommandFlag>
<Icon guid="guidImages" id="bmpPic1" />
<Strings>
<ButtonText>Invoke TestCommand</ButtonText>
</Strings>
</Button>
让VsPackage随着项目启动后就立即加载,不然动态判断逻辑无法提前指定
修改Command的初始化方法,拿到DTE,很多功能点需要用到它里面的接口,比如拿到当前选择的item
image
然后再初始化Menu的时候指定BeforeQueryStatus的逻辑为后缀为json才展示
我觉得对于visual studio中如何用插件来扩展menu 大概了解上面几点就差不多了,希望能帮助到你
有个好消息和大家分享,昨天收到通知我当选了本届的微软MVP,以后会带给大家更多的技术分享~~~
Enjoy!!!
关注公众号一起学习
手机扫一扫
移动阅读更方便
你可能感兴趣的文章