由於自 Visual Studio 2012 開始,微軟已經取消了對宏的支持,因此本篇文章所述內容只適用於 Visual Studio 2010 或更早期版本的 VS。html
在上一篇中,我已經介紹瞭如何編寫一個最簡單的宏,本文將進一步介紹如何用宏來實現對代碼編輯窗口控制。在本文結束的時候,你應該能本身實現以下兩個功能,第一個用於對方法體進行 phase0 標記;第二個能夠將當前窗口中的代碼進行歸類,將全部方法、屬性、變量經過region進行分塊。編程
動畫演示:phase0 編輯器
動畫演示:設置 region
工具
在計算機行業內,宏的出現由來已久,由於它能替代人們執行一些重複發生的簡單但煩瑣的事情,因此廣受人們歡迎。在 Visual Studio 中也提供了進行宏編程的方法,從而方便開發人員錄製一些宏腳原本擴展Visual Studio,以提升開發效率。post
要想在 Visual Studio 中操做宏來操控代碼編輯窗口,就必需要了解以下幾個東東:EnvDTE、DTE、TextSelection、EditPoint。宏可實現地遠不止是操控代碼編輯窗口,關於其它能力請見參考資源[1]。動畫
本文中的內容在閱讀過程當中最好能結合實踐進行練習,這樣印象會更深入。 ui
EnvDTE 是最核心的程序集,全部後續要講到的東西都歸於它名下。spa
MSDN上對它的介紹:3d
EnvDTE 是包含 Visual Studio 內核自動化的對象和成員的用程序集包裝的 COM 庫。 在 EnvDTE80、EnvDTE90、 EnvDTE90a 和 EnvDTE100 命名空間中包含更改和新功能。code
EnvDTE80、90、100按照數字,越大的表示越新,由於Visual Stuido有好多版本,不一樣的版本會提供新的功能,而這幾個版本的 EnvDTE 正是對應了這些更新,不一樣的版本只是在功能上作了補充,並無誰能替代誰的關係,好比editPoint2 比 editPoint 可能多了某些新特性,當你要使用這些新特性的時候,就應該使用editPoint2,不然仍是使用 editPoint。
在編寫本身的擴展前,能夠把EnvDTE、EnvDTE80 等所有引用進來。
Imports EnvDTE Imports EnvDTE80 Imports EnvDTE90 Imports EnvDTE90a Imports EnvDTE100
在 Visual Studio 中, DTE 對象是自動化模型中的頂級對象,經過操做DTE對象能夠獲取對 Visual Studio 的控制,好比你能夠獲得當前活動的文檔、活動的窗口、活動的項目、查找與替換、向解決方案中添加文件、執行預約義命令、錄製宏等。
DTE包含的屬性(局部)
上面只是截取了一部分,完整的請查看 MSDN
DTE包含的方法
經過操控這些屬性和方法就能夠實現強大的功能,下面的例子中經過操縱DTE對象的TextSelecion子對象和Find子對象來調用 Visual Studio 的查找功能。
1 Dim selection As TextSelection = DTE.ActiveDocument.Selection 2 3 DTE.Find.MatchWholeWord = False 4 DTE.Find.Action = vsFindAction.vsFindActionFind 5 DTE.Find.Target = vsFindTarget.vsFindTargetCurrentDocument 6 DTE.Find.MatchCase = False 7 DTE.Find.Backwards = False 8 DTE.Find.MatchInHiddenText = True 9 DTE.Find.PatternSyntax = vsFindPatternSyntax.vsFindPatternSyntaxLiteral 10 11 '跳出輸入框,接收你的輸入 12 what = InputBox(prompt) 13 If (what <> "") Then 14 DTE.Find.FindWhat = what 15 16 '至關於在當前文檔向下搜索一次 17 Dim result = DTE.Find.Execute() 18 If (result = vsFindResult.vsFindResultFound) Then 19 20 ’若是找到,就把那一行選中 21 selection.SelectLine() 22 End If 23 End If
上面的代碼並不複雜,就是簡單地對 Find 的調用和賦值。若是你正好看到這裏,不仿也試着寫一下吧~ Find 相關內容請查看參考資源[2]。
用於表明當前選定的區域,一個文檔有且只有一個實例,即便你在代碼中建立了多個實例,這些實例其實都是指向同一個選定區域。對 TextSelection 的操控會直接體如今界面上。經過控制該對象能夠剪切、複製、刪除選中的文本,插入刪除空白行,大小寫轉換,定位到某個位置、格式化等。
TextSelection 的屬性
TextSelection 的方法(局部)
完整的請查看 MSDN
一句話獲取 TextSelection 實例,由於 TextSelection 是針對文檔的,因此在獲取 Selection 以前,必須先獲取文檔。若是當前文檔中並無選中任何文本,則 TextSelection 表示的是當前光標所在的位置。
Dim selection As TextSelection = DTE.ActiveDocument.Selection
下面演示幾個例子,來講明 TextSelection 的能力。
第一個例子將演示如何獲取當前光標所在的方法的名稱,主要經過獲取當前光標所在位置的 CodeElement 元素來獲得具體的方法信息,經過傳入 CodeElement 的參數不一致能夠獲取不一樣塊的信息,包括方法、枚舉、屬性、類、名稱空間等。關於 vsCMElement 的枚舉請見參考資源[4]。
1 Sub DemoFunctionInfo() 2 Dim selection As TextSelection = DTE.ActiveDocument.Selection 3 Dim func As CodeFunction = selection.ActivePoint.CodeElement(vsCMElement.vsCMElementFunction) 4 If Not func Is Nothing Then 5 MsgBox(func.Name) 6 End If 7 End Sub
動畫演示:顯示方法名
第二個示例,演示如何在光標位置所在的行上下加上Region。
1 Sub DemoRegion() 2 3 '獲取 TextSelection 實例 4 Dim selection As TextSelection = DTE.ActiveDocument.Selection 5 6 '移動到當前光標所在行的最前面 7 selection.StartOfLine() 8 '在該位置插入一個新行,至關於按了下回車 9 selection.NewLine() 10 '將光標移回到新行 11 selection.LineUp() 12 '在當前光標所在的位置開始輸入文字 13 selection.Text = "#region start" 14 15 '將光標移動到下一行 16 selection.LineDown() 17 '將光標移動到行末 18 selection.EndOfLine() 19 '回車 20 selection.NewLine() 21 selection.Text = "#endregion" 22 23 '格式化 24 selection.SmartFormat() 25 26 End Sub
動畫演示:在特定行的上下添加region
再來看一個示例,用戶輸入起始和結束文字,而後自動選中位於這兩個起始結束標記之間的一段文本。
1 Sub DemoSelectTextRange() 2 3 '獲取 TextSelection 4 Dim selection As TextSelection = DTE.ActiveDocument.Selection 5 Dim startLine As Integer 6 Dim startLineOffset As Integer 7 Dim startPoint As TextPoint 8 Dim endLine As Integer 9 Dim endLineOffset As Integer 10 11 DTE.Find.Action = vsFindAction.vsFindActionFind 12 DTE.Find.MatchCase = False 13 14 '-------------- 找到起始的文字 ---------------------- 15 Dim input = InputBox("Enter a word to find as the start tag") 16 If input = "" Then 17 Exit Sub 18 End If 19 20 DTE.Find.FindWhat = input 21 Dim result As vsFindResult = DTE.Find.Execute() 22 If result <> vsFindResult.vsFindResultFound Then 23 Exit Sub 24 End If 25 26 startLineOffset = selection.BottomPoint.LineCharOffset 27 startLine = selection.BottomPoint.Line 28 '----------------------------------------------------- 29 30 '--------------- 找到結束的文字 ---------------------- 31 input = InputBox("Enter a word to find as the end tag") 32 If input = "" Then 33 Exit Sub 34 End If 35 36 DTE.Find.FindWhat = input 37 result = DTE.Find.Execute() 38 If result <> vsFindResult.vsFindResultFound Then 39 Exit Sub 40 End If 41 42 endLine = selection.TopPoint.Line 43 endLineOffset = selection.TopPoint.LineCharOffset 44 '----------------------------------------------------- 45 46 '------------- 遍歷,記錄通過的字符數用於選中 -------- 47 Dim index As Integer 48 Dim len As Integer = 0 49 50 selection.GotoLine(startLine) 51 len += selection.ActivePoint.LineLength - startLineOffset 52 For index = startLine + 1 To endLine - 1 53 selection.GotoLine(index) 54 len += selection.ActivePoint.LineLength 55 Next 56 selection.GotoLine(endLine) 57 len += endLineOffset 58 '----------------------------------------------------- 59 60 '設置起始位置 61 selection.MoveToLineAndOffset(startLine, startLineOffset) 62 'True 表示鼠標跟隨移動,len 表示要移動的字符數 63 selection.CharRight(True, len) 64 65 End Sub
動畫演示:選中一段文本
Visual Studio 除了在代碼編輯窗口中會保留代碼,還有一個叫代碼緩衝區的地方(用戶是看不到的)也會保留代碼,但這個緩衝區中的代碼不受自動換行和虛擬空格的影響。前面咱們說過 TextSelection 只能有一個,那若是開發人員事先選中了一行代碼,而咱們又在宏中不當心改變了這個 TextSelection,那就會致使用戶的選中被丟失。另外,EditPoint提供了一些TextSelection所不具有的操做能力。好比剪切一段文本,使用 EditPoint 的 Cut 方法只要設置起始位置而後直接傳入結束的位置給 Cut 方法就能夠完成,可是若是使用 TextSelection ,由於它的 Cut 不帶參數,因此就必須先選中這段文本才能使用 Cut 方法。
這裏補充一個小知識點,什麼是虛擬空格?這個東東默認是關閉的,在 Visual Studio 開發的時候也不多用。通常咱們在寫代碼的時候,若是在一行的結尾處使用小鍵盤向右繼續移動的話,光標很快就會自動跳轉到下一行。若是開啓以後,則永遠不會自動跳轉到下一行,你能夠在任意一個位置進行編輯。開啓的方式:工具 / 選項 / 文本編輯器 / 全部語言 -> 啓用虛擬空格。
因此若是你在項目中會存在自動換行或開啓了虛擬空格,那麼想要精準的控制編輯器,仍是使用 EditPoint 吧。
下面同樣舉個例子來說解。該示例將把一個方法的位置進行移動,思路就是先剪切,而後粘貼。
1 Sub DemoCut() 2 Dim selection As TextSelection = DTE.ActiveDocument.Selection 3 '獲取editPointer 4 Dim edit = selection.ActivePoint.CreateEditPoint 5 '獲取 方法 6 Dim func As CodeFunction = selection.ActivePoint.CodeElement(vsCMElement.vsCMElementFunction) 7 If Not func Is Nothing Then 8 edit.MoveToPoint(func.StartPoint) 9 edit.Cut(func.EndPoint) 10 11 edit.MoveToLineAndOffset(20, 1) 12 edit.Paste() 13 End If 14 End Sub
動畫演示:如何剪貼一個方法
辛苦了,看到這裏實在不容易。既然已經看到這了,何不來嘗試着本身寫一個呢?回到開頭的兩個示例,看看能不能寫出來了。答案請兇猛的點擊這裏。
[1] 自動化與擴展性參考
[2] Find 接口
[4] vsCMElement 枚舉
本文來源於 《Visual Studio 宏的高級用法》