首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Visual Studio 2008 擴展性開發(七):深度掌握文字編輯器擴展

     編輯:關於.NET

前文介紹方案總管操作,但開發者大多數時間面對的是編輯器。VS2008 編輯器功能已很強大,善用熱鍵編碼極為順手,正如《卓有成效的程序員》所言:「編程時始終優先使用鍵盤而非滑鼠」。但 VS 面向所有開發者,只能提供通用功能;若有額外需求,只能自己動手擴展。

AOM 中編輯器相關核心介面

1. Documents 集合

預設以標籤式呈現開啟的文件。重要成員:

  • Count、Add()、CloseAll()、Item()、Open()、SaveAll()

可遍歷取得所有文件資訊,單一文件對應 Document 介面。

2. Document 介面

代表正在編輯的文件。關鍵屬性/方法:

  • FullName/Path/Name、Language、ProjectItem、Selection、Type
  • Activate()、Close()、Redo()/Undo()、Save()

Selection 極為實用(多為先選取再操作),DTE.ActiveDocument 可快速取得作用中文件。

3. TextSelection:編輯操作與選取文字存取

功能極全面,幾乎滿足所有編輯需求,詳見 MSDN。

4. TextPoint:文件位置點

代表文件中某位置(含行號、欄號等),關鍵屬性:

  • AbsoluteCharOffset、AtEndOfDocument/Line、AtStartOfDocument/Line
  • DisplayColumn、Line、LineCharOffset、LineLength
  • CreateEditPoint():建立可編輯的 EditPoint
  • 比較方法:EqualTo()、GreaterThan()、LessThan()

5. EditPoint:真正的編輯利器

繼承 TextPoint 所有功能,另提供插入、刪除、剪貼、貼上、書籤、位置移動等編輯方法,賦予程式化編輯強大能力。

6. VirtualPoint:處理超出右邊距的文字

繼承 TextPoint,少量擴充屬性/方法,用於操作螢幕可見範圍外的文字。

7. TextDocument:編輯器中開啟文件的另一種表達

了解前幾個介面後,TextDocument 很容易上手。操作文字時多從 TextSelection 切入,特定情境下 TextDocument 為佳起點。

實戰範例:CodeTemplate 代碼模板

問題背景

專案要求每次修改程式碼需加入特定格式註解:

//-------------Change Begin------------------------------------
//-----------Code change log for Item 1001 ------------------------------
//-----------Modified by : Anders Cui Change Date: 03/30/2009
//-----------Changes Begin-------------------------------------------------
Console.WriteLine("Hello, World");
//-----------Changes End for Item 1001 ----------------------------------

雖不情願但必須重複。分析註解結構:Item 1001 為需求單號、作者、日期、包含選取代碼。曾考慮 Code Snippet,但兩大痛點:新需求需更新 Snippet、無法自動產生日期。

模板化解決方案

建立參數化模板:

//-------------Change Begin------------------------------------
//-----------Code change log for $item$ -------------------------------
//-----------Modified by : $author$ Change Date: $today$
//-----------Changes Begin-------------------------------------------------
$selected$
//-----------Changes End for $item$ ----------------------------------

將變動部分提取為參數($item$、$author$),日期設為內建參數($today$)。使用時置換參數並插入文件。對應 XML 設定檔:

<?xml version="1.0" encoding="utf-8"?>
<templates>
  <builtInParams>
    <param format="MM/dd/yyyy">today</param>
    <param format="yyyy-MM-dd">now</param>
    <param>guid</param>
    <param>solution</param>
    <param>project</param>
    <param>file</param>
  </builtInParams>
  <template name="Comment">
    <content><![CDATA[
//-------------Change Begin------------------------------------
//-----------Code change log for $item$ -------------------------------
//-----------Modified by : $author$ Change Date: $today$
//-----------Changes Begin-------------------------------------------------
$selected$
//-----------Changes End for $item$ ----------------------------------
    ]]></content>
    <params>
      <param name="item">1001</param>
      <param name="author">Anders Cui</param>
    </params>
  </template>
  <template name="Codes">...</template>
</templates>

約定:參數以 $ 包裹,$selected$ 指示選取文字插入位置。

實作細節

1. 動態建立巢狀選單

模板可多,若每個都加選單項會過長。採用彈出選單(CommandBarPopup)承載所有模板項目:

int templatePopupIndex = codeWinCommandBar.Controls.Count + 1;
CommandBarPopup codeTemplatePopup = codeWinCommandBar.Controls.Add(
  MsoControlType.msoControlPopup, Type.Missing, Type.Missing,
  templatePopupIndex, true) as CommandBarPopup;
codeTemplatePopup.Caption = "Code Template";

CommandBarButton codeTemplateCmd = helper.AddButtonToPopup(codeTemplatePopup,
  codeTemplatePopup.Controls.Count + 1, "Code Template 1", "Code Template 1");
codeTemplateCmdEvent = _applicationObject.Events.get_CommandBarEvents(codeTemplateCmd) as CommandBarEvents;
codeTemplateCmdEvent.Click += new _dispCommandBarControlEvents_ClickEventHandler(CodeTemplateCmdEvent_Click);

運行時讀取設定檔,依模板數量動態產生選單項,共用同一個事件處理函式。

2. 事件處理與文字插入優化

初版直接用 TextSelection.Text 整體替換,速度較慢。改用 EditPoint 分段寫入:

private void codeTemplateCmdEvent_Click(...) {
  CommandBarControl ctrl = CommandBarControl as CommandBarControl;
  string content = CodeTemplateManager.Instance.GetTemplateContent(ctrl.Caption);

  int indexOfSelectedParam = CodeTemplateManager.Instance.IndexOfSelectedParam(content);
  bool surroundSelectedText = (indexOfSelectedParam >= 0);

  TextSelection selected = _applicationObject.ActiveDocument.Selection as TextSelection;
  EditPoint topPoint = selected.TopPoint.CreateEditPoint();
  EditPoint bottomPoint = selected.BottomPoint.CreateEditPoint();

  if (surroundSelectedText) {
    string beforeSelectedParam = CodeTemplateManager.Instance.GetTextBeforeSelectedParam(content);
    string afterSelectedParam = CodeTemplateManager.Instance.GetTextAfterSelectedParam(content);

    topPoint.LineUp(1);
    topPoint.EndOfLine();
    topPoint.Insert(Environment.NewLine);
    topPoint.Insert(beforeSelectedParam);

    bottomPoint.EndOfLine();
    bottomPoint.Insert(Environment.NewLine);
    bottomPoint.Insert(afterSelectedParam);
  } else {
    topPoint.Delete(bottomPoint);
    topPoint.Insert(content);
  }
}

將模板拆為「選取文字前」、「選取文字本身」、「選取文字後」三段,僅在前後寫入文字,速度大幅提升。若無 $selected$ 則刪除選取內容後寫入模板。

此功能已在小團隊實戰使用,節省大量時間。

本篇小結

本文系統介紹編輯器擴展核心 API(TextSelection、TextPoint、EditPoint、VirtualPoint、TextDocument),並以參數化代碼模板為實戰範例,示範動態選單建立與高效文字插入技巧。

出處:https://anderslly.cnblogs.com

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved