逐步解說: 顯示智慧標籤
智慧標籤會展開以顯示一組巨集的標籤文字。 比方說,在 Visual Basic 或視覺化 C# 的專案中,一條紅線出現在 [文字] 下重新命名的識別項,例如變數名稱時。 當您將指標移底線時,按鈕會顯示指標附近。 如果您按一下按鈕時,建議的動作會顯示,比方說, 重新命名為 IsReady 的 IsRead。 如果按一下 [動作],會重新命名專案中的所有參考到 IsRead IsReady。
雖然智慧標籤是在編輯器中的 IntelliSense 實作的一部分,您可以由子類別化,實作智慧標籤SmartTag,然後再實作ITagger介面和IViewTaggerProvider介面。
![]() |
---|
以類似的方式,可以實作其他種類的標籤。 |
下列逐步解說會示範如何建立智慧標籤,就會出現在目前的文字,並有兩個建議的動作: 轉換成大寫 和 轉換成小寫字母。
必要條件
若要完成這個逐步解說中,您必須安裝Visual Studio 2010 SDK。
![]() |
---|
如需有關 Visual Studio 的 SDK 的詳細資訊,請參閱擴充 Visual Studio 的概觀。若要了解如何下載 Visual Studio 的 SDK,請參閱Visual Studio 擴充性開發人員中心 MSDN 網站上。 |
建立受管理的擴充性架構 (MEF) 專案
若要建立 MEF 專案
建立編輯器類別器的專案。 為方案命名 SmartTagTest。
VSIX 資訊清單編輯器中開啟 source.extension.vsixmanifest 檔案。
請確定Content名包含 MEF 元件的內容類型,並Path設定為 SmartTagTest.dll。
儲存並關閉 source.extension.vsixmanifest。
將下列參考加入至專案,並設定 CopyLocal 到false:
Microsoft.VisualStudio.Language.Intellisense
刪除現有的類別檔案。
智慧標籤實作的 Tagger
若要實作智慧標籤的 tagger
將類別檔案,並命名為 TestSmartTag。
加入下列匯入:
Imports System Imports System.Collections.Generic Imports System.ComponentModel.Composition Imports System.Collections.ObjectModel Imports System.Windows.Media Imports Microsoft.VisualStudio.Language.Intellisense Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Operations Imports Microsoft.VisualStudio.Text.Tagging Imports Microsoft.VisualStudio.Utilities
using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.Collections.ObjectModel; using System.Windows.Media; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Text.Tagging; using Microsoft.VisualStudio.Utilities;
新增類別,名為TestSmartTag繼承自SmartTag。
Friend Class TestSmartTag Inherits SmartTag
internal class TestSmartTag : SmartTag
加入具有基底建構函式會呼叫這個類別的建構函式SmartTagType的Factoid,這樣將會造成在下一個字的第一個字元出現在藍色線條。 (如果您使用Ephemeral,一條紅線會出現這個字的最後一個字元下。)
Public Sub New(ByVal actionSets As ReadOnlyCollection(Of SmartTagActionSet)) MyBase.New(SmartTagType.Factoid, actionSets) End Sub
public TestSmartTag(ReadOnlyCollection<SmartTagActionSet> actionSets) : base(SmartTagType.Factoid, actionSets) { }
新增類別,名為TestSmartTagger繼承自ITagger型別的TestSmartTag,並實作IDisposable。
Friend Class TestSmartTagger Implements ITagger(Of TestSmartTag), IDisposable
internal class TestSmartTagger : ITagger<TestSmartTag>, IDisposable
將下列私用欄位加入 tagger 類別。
Private m_buffer As ITextBuffer Private m_view As ITextView Private m_provider As TestSmartTaggerProvider Private m_disposed As Boolean
private ITextBuffer m_buffer; private ITextView m_view; private TestSmartTaggerProvider m_provider; private bool m_disposed;
新增的建構函式將私用欄位中,然後訂閱LayoutChanged事件。
Public Sub New(ByVal buffer As ITextBuffer, ByVal view As ITextView, ByVal provider As TestSmartTaggerProvider) m_buffer = buffer m_view = view m_provider = provider AddHandler m_view.LayoutChanged, AddressOf OnLayoutChanged End Sub
public TestSmartTagger(ITextBuffer buffer, ITextView view, TestSmartTaggerProvider provider) { m_buffer = buffer; m_view = view; m_provider = provider; m_view.LayoutChanged += OnLayoutChanged; }
實作GetTags ,以便為目前的文字建立標籤。 (此方法也會呼叫私用方法GetSmartTagActions ,稍後會加以說明。)
Public Function GetTags(ByVal spans As NormalizedSnapshotSpanCollection) As IEnumerable(Of ITagSpan(Of TestSmartTag)) Implements ITagger(Of TestSmartTag).GetTags Dim snapshot As ITextSnapshot = m_buffer.CurrentSnapshot If snapshot.Length = 0 Then Return Nothing Exit Function End If 'set up the navigator Dim navigator As ITextStructureNavigator = m_provider.NavigatorService.GetTextStructureNavigator(m_buffer) 'set up a list to contain the tags Dim list As List(Of TagSpan(Of TestSmartTag)) list = New List(Of TagSpan(Of TestSmartTag))() For Each span In spans Dim caret As ITextCaret = m_view.Caret Dim point As SnapshotPoint If CInt(caret.Position.BufferPosition) > 0 Then point = caret.Position.BufferPosition - 1 Else Exit For End If Dim extent As TextExtent = navigator.GetExtentOfWord(point) 'don't display the tag if the extent has whitespace If extent.IsSignificant Then list.Add(New TagSpan(Of TestSmartTag)(extent.Span, New TestSmartTag(GetSmartTagActions(extent.Span)))) Else Exit For End If Next span Return list End Function
public IEnumerable<ITagSpan<TestSmartTag>> GetTags(NormalizedSnapshotSpanCollection spans) { ITextSnapshot snapshot = m_buffer.CurrentSnapshot; if (snapshot.Length == 0) yield break; //don't do anything if the buffer is empty //set up the navigator ITextStructureNavigator navigator = m_provider.NavigatorService.GetTextStructureNavigator(m_buffer); foreach (var span in spans) { ITextCaret caret = m_view.Caret; SnapshotPoint point; if (caret.Position.BufferPosition > 0) point = caret.Position.BufferPosition - 1; else yield break; TextExtent extent = navigator.GetExtentOfWord(point); //don't display the tag if the extent has whitespace if (extent.IsSignificant) yield return new TagSpan<TestSmartTag>(extent.Span, new TestSmartTag(GetSmartTagActions(extent.Span))); else yield break; } }
新增GetSmartTagActions方法,以設定 [智慧標籤動作。 在後面幾個步驟中實作本身的動作。
Private Function GetSmartTagActions(ByVal span As SnapshotSpan) As ReadOnlyCollection(Of SmartTagActionSet) Dim actionSetList As New List(Of SmartTagActionSet)() Dim actionList As New List(Of ISmartTagAction)() Dim trackingSpan As ITrackingSpan = span.Snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeInclusive) actionList.Add(New UpperCaseSmartTagAction(trackingSpan)) actionList.Add(New LowerCaseSmartTagAction(trackingSpan)) Dim actionSet As New SmartTagActionSet(actionList.AsReadOnly()) actionSetList.Add(actionSet) Return actionSetList.AsReadOnly() End Function
private ReadOnlyCollection<SmartTagActionSet> GetSmartTagActions(SnapshotSpan span) { List<SmartTagActionSet> actionSetList = new List<SmartTagActionSet>(); List<ISmartTagAction> actionList = new List<ISmartTagAction>(); ITrackingSpan trackingSpan = span.Snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeInclusive); actionList.Add(new UpperCaseSmartTagAction(trackingSpan)); actionList.Add(new LowerCaseSmartTagAction(trackingSpan)); SmartTagActionSet actionSet = new SmartTagActionSet(actionList.AsReadOnly()); actionSetList.Add(actionSet); return actionSetList.AsReadOnly(); }
宣告SmartTagsChanged事件。
Public Event TagsChanged As EventHandler(Of SnapshotSpanEventArgs) Implements ITagger(Of TestSmartTag).TagsChanged
public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
實作OnLayoutChanged要引發的事件處理常式TagsChanged事件,這可以讓GetTags呼叫。
Private Sub OnLayoutChanged(ByVal sender As Object, ByVal e As TextViewLayoutChangedEventArgs) Dim snapshot As ITextSnapshot = e.NewSnapshot 'don't do anything if this is just a change in case If Not snapshot.GetText().ToLower().Equals(e.OldSnapshot.GetText().ToLower()) Then Dim span As New SnapshotSpan(snapshot, New Span(0, snapshot.Length)) Dim handler As EventHandler(Of SnapshotSpanEventArgs) = Me.TagsChangedEvent If handler IsNot Nothing Then handler(Me, New SnapshotSpanEventArgs(span)) End If End If End Sub
private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e) { ITextSnapshot snapshot = e.NewSnapshot; //don't do anything if this is just a change in case if (!snapshot.GetText().ToLower().Equals(e.OldSnapshot.GetText().ToLower())) { SnapshotSpan span = new SnapshotSpan(snapshot, new Span(0, snapshot.Length)); EventHandler<SnapshotSpanEventArgs> handler = this.TagsChanged; if (handler != null) { handler(this, new SnapshotSpanEventArgs(span)); } } }
實作Dispose方法,讓它取消訂閱從LayoutChanged事件。
Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub Private Sub Dispose(ByVal disposing As Boolean) If disposing Then RemoveHandler m_view.LayoutChanged, AddressOf OnLayoutChanged m_view = Nothing End If m_disposed = True End Sub
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (!this.m_disposed) { if (disposing) { m_view.LayoutChanged -= OnLayoutChanged; m_view = null; } m_disposed = true; } }
實作智慧標籤 Tagger 提供者
若要實作智慧標籤 tagger 提供者
新增類別,名為TestSmartTagTaggerProvider繼承自IViewTaggerProvider。 匯出與ContentTypeAttribute的 「 文字 」, OrderAttribute的早於 ="default",和TagTypeAttribute的SmartTag。
<Export(GetType(IViewTaggerProvider))> <ContentType("text")> <Order(Before:="default")> <TagType(GetType(SmartTag))> Friend Class TestSmartTaggerProvider Implements IViewTaggerProvider
[Export(typeof(IViewTaggerProvider))] [ContentType("text")] [Order(Before = "default")] [TagType(typeof(SmartTag))] internal class TestSmartTaggerProvider : IViewTaggerProvider
匯入ITextStructureNavigatorSelectorService做為屬性。
<Import(GetType(ITextStructureNavigatorSelectorService))> Friend Property NavigatorService() As ITextStructureNavigatorSelectorService
[Import(typeof(ITextStructureNavigatorSelectorService))] internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
實作 CreateTagger``1 方法。
Public Function CreateTagger(Of T As ITag)(ByVal textView As ITextView, ByVal buffer As ITextBuffer) As ITagger(Of T) Implements IViewTaggerProvider.CreateTagger If buffer Is Nothing OrElse textView Is Nothing Then Return Nothing End If 'make sure we are tagging only the top buffer If buffer Is textView.TextBuffer Then Return New TestSmartTagger(buffer, textView, Me) Else Return Nothing End If End Function
public ITagger<T> CreateTagger<T>(ITextView textView, ITextBuffer buffer) where T : ITag { if (buffer == null || textView == null) { return null; } //make sure we are tagging only the top buffer if (buffer == textView.TextBuffer) { return new TestSmartTagger(buffer, textView, this) as ITagger<T>; } else return null; }
實作智慧標籤動作
若要實作智慧標籤動作
建立兩個類別,第一個名為 UpperCaseSmartTagAction ,而第二個名為 LowerCaseSmartTagAction。 這兩個類別會實作ISmartTagAction。
Friend Class UpperCaseSmartTagAction Implements ISmartTagAction
internal class UpperCaseSmartTagAction : ISmartTagAction
Friend Class LowerCaseSmartTagAction Implements ISmartTagAction
internal class LowerCaseSmartTagAction : ISmartTagAction
這兩個類別是相同的不同之處在於其中一個會呼叫ToUpper及其他呼叫ToLower。 下列步驟涵蓋只有大寫動作類別,但您必須實作這兩個類別。 請使用步驟的實作模式實作的大小寫的動作為大寫的動作。
宣告一組的私用欄位。
Private m_span As ITrackingSpan Private m_upper As String Private m_display As String Private m_snapshot As ITextSnapshot
private ITrackingSpan m_span; private string m_upper; private string m_display; private ITextSnapshot m_snapshot;
加入建構函式所設定的欄位。
Public Sub New(ByVal span As ITrackingSpan) m_span = span m_snapshot = span.TextBuffer.CurrentSnapshot m_upper = span.GetText(m_snapshot).ToUpper() m_display = "Convert to upper case" End Sub
public UpperCaseSmartTagAction(ITrackingSpan span) { m_span = span; m_snapshot = span.TextBuffer.CurrentSnapshot; m_upper = span.GetText(m_snapshot).ToUpper(); m_display = "Convert to upper case"; }
以下列方式實作的屬性。
Public ReadOnly Property DisplayText() As String Implements ISmartTagAction.DisplayText Get Return m_display End Get End Property Public ReadOnly Property Icon() As ImageSource Implements ISmartTagAction.Icon Get Return Nothing End Get End Property Public ReadOnly Property IsEnabled() As Boolean Implements ISmartTagAction.IsEnabled Get Return True End Get End Property Private privateSource As ISmartTagSource Public Property Source() As ISmartTagSource Get Return privateSource End Get Private Set(ByVal value As ISmartTagSource) privateSource = value End Set End Property Public ReadOnly Property ActionSets() As ReadOnlyCollection(Of SmartTagActionSet) Implements ISmartTagAction.ActionSets Get Return Nothing End Get End Property
public string DisplayText { get { return m_display; } } public ImageSource Icon { get { return null; } } public bool IsEnabled { get { return true; } } public ISmartTagSource Source { get; private set; } public ReadOnlyCollection<SmartTagActionSet> ActionSets { get { return null; } }
實作Invoke以同等項目取代的文字範圍中的方法。
Public Sub Invoke() Implements ISmartTagAction.Invoke m_span.TextBuffer.Replace(m_span.GetSpan(m_snapshot), m_upper) End Sub
public void Invoke() { m_span.TextBuffer.Replace(m_span.GetSpan(m_snapshot), m_upper); }
建置和測試程式碼
若要測試這段程式碼,建置 SmartTagTest 方案並執行它實驗性的執行個體中。
若要建置和測試 SmartTagTest 的解決方案
建置方案。
當您執行此專案在偵錯工具時,會執行個體化 Visual Studio 的第二個執行個體。
建立一個文字檔,並輸入一些文字。
在 [文字的第一個單字的第一個字母] 下,應該會顯示藍線。
指標移動過藍線。
指標附近,應該會顯示一個按鈕。
當您按一下按鈕時,兩個建議的動作應該會顯示: 轉換成大寫 和 轉換成小寫字母。 如果您按一下第一個動作時,就應該在目前的 word 中的所有文字都轉換成大寫。 如果您按一下第二個動作時,所有的文字應轉換成小寫字母。