由於此功能需要在右鍵菜單上添加命令,所以選擇Visual Studio Package模板,根據模板向導步驟插件項目,在Select VSPackage Options步驟的時候選擇Menu Command選項,如圖-1所示:
圖-1
接下來是設置命令的名稱,如圖-2所示
圖-4
Button元素的guid和id屬性是該命令的唯一標識,這兩個屬性值分別在項目的Guids.cs和PkgCmdID.cs文件裡定義了,priority表示命令在目標菜單的排列優先級。Parent子元素表示要將我們的命令添加到哪個菜單下面,如工具、幫助、右鍵菜單,id屬性的值是Group元素的id屬性值,如圖-4所示。Icon元素是命令前的小圖標,其屬性值是在GuidSymbol元素定義的,如圖-6所示。
圖-5
Group元素定義了目標菜單的guid和id,也可以將圖-4的guid和id換成guidSHLMainMenu和IDM_VS_MENU_TOOLS,這兩種效果是一樣的,都是將命令添加到右鍵菜單裡。如果要按照圖-4的方式設置guid和id值的話,需要事先知道目標菜單的guid和id值,並且要在Sysmbols元素裡定義guid和id,如圖-5所示:
圖-6
除了紅色框裡的元素是我們自己定義的,其他的都是向導自動生成。那麼為什麼使用guidSHLMainMenu和IDM_VS_MENU_TOOLS作為guid和id兩個屬性的值的時候就需要在Sysmbols元素裡定義了呢?因為這兩個元素的值已經在stdidcmd.h和vsshlids.h(C:\Program Files (x86)\Microsoft Visual Studio 12.0\VSSDK\VisualStudioIntegration\Common\Inc)這兩個文件裡定義了,而這兩個文件已經在vsct文件的開頭就已經使用Extern元素引入了,所以就不需要我們再去定義了。
1、打開注冊表編輯器(打開運行窗口,輸入regedit),在[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\12.0\General]找到該路徑,右擊-新建-DWORD(32-位)值(D),建立一個注冊文件,將其命名為EnableVSIPLogging,並將其值改為1。按下Ctrl+Shift,用鼠標點擊VS裡的菜單,就會彈出一個VSDebug Message窗口,如圖-6所示:
圖-7
其中Guid和CmdID值就是我們需要的,NameLoc表示我們點擊的菜單名稱。
由於命令關聯的操作都是在點擊命令的時候才調用的,所以要實現此功能需要四個步驟才能實現:
1、在Button元素加入子元素<CommandFlag>DynamicVisibility</CommandFlag>
2、為Package類加入特性ProvideAutoLoad,該特性表示當滿足條件的時候,事先加載該類裡的相關運行。而條件是由該特性的構造函數來設置的,相關的條件已經定義為UIContextGuids80抽象類的常量字段了。
3、將Initialize方法裡的MenuCommand類改為OleMenuCommand類,並訂閱OleMenuCommand類實例的BeforeQueryStatus事件,如圖-8所示:
圖-8
4、在BeforeQueryStatus事件處理函數裡顯示控制操作,如控制命令只在xml文件的右鍵菜單裡才能顯示,代碼如下所示:
1 private void menuItem_BeforeQueryStatus(object sender, EventArgs e)
2 {
3 OleMenuCommand menuCommand = sender as OleMenuCommand;
4 if (menuCommand != null)
5 {
6 IntPtr hierarchyPtr, selectionContainerPtr;
7 uint projectItemId;
8 IVsMultiItemSelect mis;
9 IVsMonitorSelection monitorSelection = (IVsMonitorSelection)Package.GetGlobalService(typeof(SVsShellMonitorSelection));
10 monitorSelection.GetCurrentSelection(out hierarchyPtr, out projectItemId, out mis, out selectionContainerPtr);
11
12 IVsHierarchy hierarchy = Marshal.GetTypedObjectForIUnknown(hierarchyPtr, typeof(IVsHierarchy)) as IVsHierarchy;
13 if (hierarchy != null)
14 {
15 object value;
16 hierarchy.GetProperty(projectItemId, (int)__VSHPROPID.VSHPROPID_Name, out value);
17
18 if (value != null && value.ToString().EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
19 {
20 menuCommand.Visible = true;
21 }
22 else
23 {
24 menuCommand.Visible = false;
25 }
26 }
27 }
28 }
到此,在xml文件的右鍵菜單裡添加命令的功能已經實現。如圖-9所示:
圖-9
添加功能可以在MenuItemCallBack事件處理函數裡進行操作,需要判斷當前的xml文件是否是新建的,如果是需要加上根元素,為了防止用戶是在根元素所在行的後面點擊命令(這樣就找不到根元素),所以在開始查找操作之前需要將光標移到第一行,然後根據查找的結果判斷是否需要添加根元素。如果是新建的xml文件的話可以直接將xml元素信息添加到第一行後面,如果已經存在根元素,則將根元素的結束元素替換成xml元素信息,代碼如下所示:
DTE dte = ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE;
if (dte == null)
return;
TextSelection ts = dte.ActiveDocument.Selection as TextSelection;
//防止用戶在</mappings>結束符後進行操作,在結束符後操作的的FindText方法返回的結果為false
ts.MoveToLineAndOffset(1, 1);
bool result = ts.FindText("</mappings>",(int)vsFindOptions.vsFindOptionsMatchWholeWord);
if (!result)
{
if (ts.ActivePoint.Line == 1)
{
ts.EndOfLine();
ts.NewLine();
}
string str = "<mappings>\r\n" + sb.ToString();
ts.Insert(str);
}
else
{
//需要添加此操作,否則不會替換成功
ts.SelectAll();
ts.ReplacePattern("</mappings>", sb.ToString(), (int)vsFindOptions.vsFindOptionsMatchWholeWord);
}