工欲善其事,必先利其器,作為程式設計師我們很大部分時間在和ide打交道,好的外掛可以大大提高我們的程式設計效率,我開發過幾個vs外掛來解決一鍵生成dbmodels,快速部署到伺服器,總結下來最關鍵的還是對於Menu這塊的擴充套件,因為這是外掛功能的最常見的入口之一,下面給大家介紹vs外掛各種menu的擴充套件
這裡我使用vs2022版本,要開發vs外掛的話,需要vs安裝外掛開發模組
開啟vs 然後點選 工具 -> 獲取工具和功能
然後勾選Visual Studio擴充套件開發
安裝好之後,開啟vs就可以選擇到 vsix project 模板了
我們利用vsix project模板建立一個外掛工程
空的vsix project就建立成功了,我們新增一個command(選單操作)
建立了一個Command會新增下面3個
點選啟動這個外掛,會開啟一個有外掛環境的vs(隔離的)
會看到我們的Command名稱:Invoke TestCommand按鈕在vs的[工具]這個選單裡面, 點選它會出一個彈框,如下
好了,以上完成初體驗後,回到本文要重點介紹:vs的Menu擴充套件
上面我們說到 vsct檔案,我們的按鈕是展示在Vs哪種型別的Menu下,就是在這個檔案定義的,我們一起看下這個vsct檔案,關鍵部分我都用不同顏色來高亮顯示
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,導致可讀性很差和難維護!
https://github.com/MicrosoftDocs/visualstudio-docs/blob/main/docs/extensibility/internals/designing-xml-command-table-dot-vsct-files.md
<Groups>
<Group guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup" priority="0x0600">
<!-- 這個guid和id決定了選單的位置 -->
<Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
</Group>
</Groups>
如果想要展示在vs的下面這些選單裡面,直接可以用上面的方式 修改id就可以了
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
https://learn.microsoft.com/en-us/visualstudio/extensibility/internals/guids-and-ids-of-visual-studio-menus?view=vs-2022
比如我把上面的demo改成這樣
<Groups>
<Group guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup" priority="0x0600">
<!-- 工程檔案右鍵選單 -->
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_PROJNODE"/>
</Group>
</Groups>
改成這樣就會顯示在程式碼視窗的右鍵選單中
<Groups>
<Group guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup" priority="0x0600">
<!-- 程式碼視窗的右鍵選單操作 -->
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN"/>
</Group>
</Groups>
所以一級選單隻需要新增一個Group 並且設定該Group的Parent為已知的定義ID即可
這裡需要新增Menu了 且 一級選單項要定義為Menu而不是Button!!
先新建一個group1以**右鍵選單為parent(已知定義ID)**,以group1為parent,再定義一個group2以一級選單Menu為parent,再將二級選單項定義為Button並以group2為parent
有點繞吧,比如我要在工程檔案的右鍵選單 新增一個二級選單,像下面這樣子
<Group guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup1" priority="0x0600">
<!--定義在標頭檔案的已知定義ID -->
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_PROJNODE"/>
</Group>
<Menus>
<Menu guid ="guidMenuDemoVSIXPackageCmdSet" id="MyMenu" priority="0x3110" type="Menu">
<Parent guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup1"/>
<Strings>
<ButtonText>New</ButtonText>
<CommandName>New</CommandName>
</Strings>
</Menu>
</Menus>
<Group guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup2" priority="0x0600">
<Parent guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenu"/>
</Group>
<Buttons>
<Button guid="guidMenuDemoVSIXPackageCmdSet" id="TestCommandId" priority="0x0100" type="Button">
<Parent guid="guidMenuDemoVSIXPackageCmdSet" id="MyMenuGroup2" />
<Icon guid="guidImages" id="bmpPic1" />
<Strings>
<ButtonText>Invoke TestCommand</ButtonText>
</Strings>
</Button>
</Buttons>
完整定義:
比如 我既要顯示在工程右鍵選單裡面,又要顯示在普通檔案的右鍵選單,又要顯示在程式碼右鍵選單
這裡就用到上面提到的 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>
效果如下:
比如 ,非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
然後再初始化Menu的時候指定BeforeQueryStatus的邏輯為字尾為json才展示
我覺得對於visual studio中如何用外掛來擴充套件menu 大概瞭解上面幾點就差不多了,希望能幫助到你
有個好訊息和大家分享,昨天收到通知我當選了本屆的微軟MVP,以後會帶給大家更多的技術分享~~~
Enjoy!!!
關注公眾號一起學習