逐步解說︰ 顯示 QuickInfo 工具提示
如需 Visual Studio 2017 的最新文件請參閱 Visual Studio 2017 文件。
QuickInfo 是 IntelliSense 功能,以顯示方法簽章,說明當使用者將指標移方法名稱。 您可以實作語言為基礎的功能,例如 QuickInfo 定義您要提供 QuickInfo 描述的識別碼,然後再建立要顯示的內容中的工具提示。 您可以定義 QuickInfo 中的內容語言服務,您可以定義您的檔案名稱副檔名和內容類型,並顯示只是該型別的 QuickInfo 或對於現有的內容類型 (例如 「 文字 」),您可以顯示 QuickInfo。 本逐步解說示範如何顯示 QuickInfo 「 文字 」 內容類型。
當使用者將指標移方法名稱,在此逐步解說 QuickInfo 則會顯示工具提示。 此設計會要求您實作這些介面,四個︰
來源介面
來源提供者介面
控制器介面
控制站提供者介面
來源和控制站的提供者是 Managed Extensibility Framework (MEF) 元件組件,而且負責匯出來源和控制器類別和匯入服務,並不會如代理人ITextBufferFactoryService,這樣就可以建立工具提示文字緩衝區,而IQuickInfoBroker,而觸發 QuickInfo 工作階段。
在此範例中,QuickInfo 來源會使用硬式編碼清單的方法名稱和描述,但在完整的實作中,語言服務和語言文件是負責提供該內容。
必要條件
啟動 Visual Studio 2015 中,您未安裝 Visual Studio SDK 從 「 下載中心 」。 它是 Visual Studio 安裝程式的選用功能。 您也可以在稍後安裝 VS SDK。 如需詳細資訊,請參閱安裝 Visual Studio SDK。
建立 MEF 專案
建立 MEF 專案
建立 C# VSIX 專案。 (在新的專案對話方塊中,選取Visual C# / 擴充性,然後VSIX 專案。)將方案命名為
QuickInfoTest
。將編輯器分類項目範本加入至專案。 如需詳細資訊,請參閱編輯器項目範本以建立副檔名為。
刪除現有類別檔案。
實作 QuickInfo 來源
QuickInfo 來源負責收集一組識別項和其描述和內容加入工具提示文字緩衝區時遇到的其中一個識別碼。 在此範例中,識別項和其說明剛加入來源建構函式。
若要實作 QuickInfo 來源
將類別檔案,並將它
TestQuickInfoSource
。加入 Microsoft.VisualStudio.Language.IntelliSense 的參考。
新增下列匯入。
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel.Composition; 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;
Imports System Imports System.Collections.Generic Imports System.Linq Imports System.Text Imports System.Collections.ObjectModel Imports System.ComponentModel.Composition 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
宣告類別可實作IQuickInfoSource,並將其命名
TestQuickInfoSource
。internal class TestQuickInfoSource : IQuickInfoSource
Friend Class TestQuickInfoSource Implements IQuickInfoSource
將欄位加入 QuickInfo 來源提供者、 文字緩衝區,和一組方法名稱和方法簽章。 在此範例中,方法名稱和簽章會在初始化
TestQuickInfoSource
建構函式。private TestQuickInfoSourceProvider m_provider; private ITextBuffer m_subjectBuffer; private Dictionary<string, string> m_dictionary;
Private m_provider As TestQuickInfoSourceProvider Private m_subjectBuffer As ITextBuffer Private m_dictionary As Dictionary(Of String, String)
新增的建構函式設定 QuickInfo 來源提供者和文字緩衝區,並於其中填入一組方法名稱和方法簽名碼和描述。
public TestQuickInfoSource(TestQuickInfoSourceProvider provider, ITextBuffer subjectBuffer) { m_provider = provider; m_subjectBuffer = subjectBuffer; //these are the method names and their descriptions m_dictionary = new Dictionary<string, string>(); m_dictionary.Add("add", "int add(int firstInt, int secondInt)\nAdds one integer to another."); m_dictionary.Add("subtract", "int subtract(int firstInt, int secondInt)\nSubtracts one integer from another."); m_dictionary.Add("multiply", "int multiply(int firstInt, int secondInt)\nMultiplies one integer by another."); m_dictionary.Add("divide", "int divide(int firstInt, int secondInt)\nDivides one integer by another."); }
Public Sub New(ByVal provider As TestQuickInfoSourceProvider, ByVal subjectBuffer As ITextBuffer) m_provider = provider m_subjectBuffer = subjectBuffer 'these are the method names and their descriptions m_dictionary = New Dictionary(Of String, String)() m_dictionary.Add("add", "int add(int firstInt, int secondInt)" & vbLf & "Adds one integer to another.") m_dictionary.Add("subtract", "int subtract(int firstInt, int secondInt)" & vbLf & "Subtracts one integer from another.") m_dictionary.Add("multiply", "int multiply(int firstInt, int secondInt)" & vbLf & "Multiplies one integer by another.") m_dictionary.Add("divide", "int divide(int firstInt, int secondInt)" & vbLf & "Divides one integer by another.") End Sub
實作AugmentQuickInfoSession方法。 在此範例中,此方法會尋找目前的文字或前一個字如果游標位於線條或文字緩衝區的結尾。 如果文字是其中一個方法名稱,該方法名稱的描述會加入 QuickInfo 內容。
public void AugmentQuickInfoSession(IQuickInfoSession session, IList<object> qiContent, out ITrackingSpan applicableToSpan) { // Map the trigger point down to our buffer. SnapshotPoint? subjectTriggerPoint = session.GetTriggerPoint(m_subjectBuffer.CurrentSnapshot); if (!subjectTriggerPoint.HasValue) { applicableToSpan = null; return; } ITextSnapshot currentSnapshot = subjectTriggerPoint.Value.Snapshot; SnapshotSpan querySpan = new SnapshotSpan(subjectTriggerPoint.Value, 0); //look for occurrences of our QuickInfo words in the span ITextStructureNavigator navigator = m_provider.NavigatorService.GetTextStructureNavigator(m_subjectBuffer); TextExtent extent = navigator.GetExtentOfWord(subjectTriggerPoint.Value); string searchText = extent.Span.GetText(); foreach (string key in m_dictionary.Keys) { int foundIndex = searchText.IndexOf(key, StringComparison.CurrentCultureIgnoreCase); if (foundIndex > -1) { applicableToSpan = currentSnapshot.CreateTrackingSpan ( //querySpan.Start.Add(foundIndex).Position, 9, SpanTrackingMode.EdgeInclusive extent.Span.Start + foundIndex, key.Length, SpanTrackingMode.EdgeInclusive ); string value; m_dictionary.TryGetValue(key, out value); if (value != null) qiContent.Add(value); else qiContent.Add(""); return; } } applicableToSpan = null; }
Public Sub AugmentQuickInfoSession(ByVal session As IQuickInfoSession, ByVal qiContent As IList(Of Object), ByRef applicableToSpan As ITrackingSpan) Implements IQuickInfoSource.AugmentQuickInfoSession ' Map the trigger point down to our buffer. Dim subjectTriggerPoint As System.Nullable(Of SnapshotPoint) = session.GetTriggerPoint(m_subjectBuffer.CurrentSnapshot) If Not subjectTriggerPoint.HasValue Then applicableToSpan = Nothing Exit Sub End If Dim currentSnapshot As ITextSnapshot = subjectTriggerPoint.Value.Snapshot Dim querySpan As New SnapshotSpan(subjectTriggerPoint.Value, 0) 'look for occurrences of our QuickInfo words in the span Dim navigator As ITextStructureNavigator = m_provider.NavigatorService.GetTextStructureNavigator(m_subjectBuffer) Dim extent As TextExtent = navigator.GetExtentOfWord(subjectTriggerPoint.Value) Dim searchText As String = extent.Span.GetText() For Each key As String In m_dictionary.Keys Dim foundIndex As Integer = searchText.IndexOf(key, StringComparison.CurrentCultureIgnoreCase) If foundIndex > -1 Then 'applicableToSpan = currentSnapshot.CreateTrackingSpan(querySpan.Start.Add(foundIndex).Position, 9, SpanTrackingMode.EdgeInclusive) applicableToSpan = currentSnapshot.CreateTrackingSpan(extent.Span.Start + foundIndex, key.Length, SpanTrackingMode.EdgeInclusive) Dim value As String = "" m_dictionary.TryGetValue(key, value) If value IsNot Nothing Then qiContent.Add(value) Else qiContent.Add("") End If Exit Sub End If Next applicableToSpan = Nothing End Sub
您必須也實作 dispose () 方法,因為IQuickInfoSource實作IDisposable:
private bool m_isDisposed; public void Dispose() { if (!m_isDisposed) { GC.SuppressFinalize(this); m_isDisposed = true; } }
Private m_isDisposed As Boolean Public Sub Dispose() Implements IDisposable.Dispose If Not m_isDisposed Then GC.SuppressFinalize(Me) m_isDisposed = True End If End Sub
實作 QuickInfo 來源提供者
QuickInfo 來源提供者做主要是為了做為 MEF 元件組件來匯出自己並具現化 QuickInfo 來源。 因為它是 MEF 元件組件時,它可以匯入其他 MEF 元件組件。
若要實作 QuickInfo 來源提供者
宣告名為 QuickInfo 來源提供者
TestQuickInfoSourceProvider
實作IQuickInfoSourceProvider,並將它與匯出NameAttribute的 「 工具提示 QuickInfo 來源 」, OrderAttribute的之前 = 「 預設 」,和ContentTypeAttribute為 [文字]。[Export(typeof(IQuickInfoSourceProvider))] [Name("ToolTip QuickInfo Source")] [Order(Before = "Default Quick Info Presenter")] [ContentType("text")] internal class TestQuickInfoSourceProvider : IQuickInfoSourceProvider
<Export(GetType(IQuickInfoSourceProvider))> _ <Name("ToolTip QuickInfo Source")> _ <Order(Before:=" Default Quick Info Presenter")> _ <ContentType("text")> _ Friend Class TestQuickInfoSourceProvider Implements IQuickInfoSourceProvider
匯入兩個編輯器服務, ITextStructureNavigatorSelectorService和ITextBufferFactoryService,以做為屬性
TestQuickInfoSourceProvider
。[Import] internal ITextStructureNavigatorSelectorService NavigatorService { get; set; } [Import] internal ITextBufferFactoryService TextBufferFactoryService { get; set; }
Private _NavigatorService As ITextStructureNavigatorSelectorService <Import()> _ Friend Property NavigatorService() As ITextStructureNavigatorSelectorService Get Return _NavigatorService End Get Set(ByVal value As ITextStructureNavigatorSelectorService) _NavigatorService = value End Set End Property Private _TextBufferFactoryService As ITextBufferFactoryService <Import()> _ Friend Property TextBufferFactoryService() As ITextBufferFactoryService Get Return _TextBufferFactoryService End Get Set(ByVal value As ITextBufferFactoryService) _TextBufferFactoryService = value End Set End Property
實作TryCreateQuickInfoSource來傳回新
TestQuickInfoSource
。public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer) { return new TestQuickInfoSource(this, textBuffer); }
Public Function TryCreateQuickInfoSource(ByVal textBuffer As ITextBuffer) As IQuickInfoSource Implements IQuickInfoSourceProvider.TryCreateQuickInfoSource Return New TestQuickInfoSource(Me, textBuffer) End Function
實作 QuickInfo 控制器
QuickInfo 控制站會決定何時應該顯示 QuickInfo。 在此範例中,透過對應至其中一個方法名稱的文字指標時,會顯示 QuickInfo。 QuickInfo 控制器實作觸發程序 QuickInfo 工作階段的滑鼠停留事件處理常式。
若要實作 QuickInfo 控制器
宣告類別可實作IIntellisenseController,並將其命名
TestQuickInfoController
。internal class TestQuickInfoController : IIntellisenseController
Friend Class TestQuickInfoController Implements IIntellisenseController
加入私用欄位的 [文字] 檢視中,以表示文字檢視、 QuickInfo 工作階段,並 QuickInfo controller 提供者的文字緩衝區。
private ITextView m_textView; private IList<ITextBuffer> m_subjectBuffers; private TestQuickInfoControllerProvider m_provider; private IQuickInfoSession m_session;
Private m_textView As ITextView Private m_subjectBuffers As IList(Of ITextBuffer) Private m_provider As TestQuickInfoControllerProvider Private m_session As IQuickInfoSession
新增設定欄位並將滑鼠停留事件處理常式的建構函式。
internal TestQuickInfoController(ITextView textView, IList<ITextBuffer> subjectBuffers, TestQuickInfoControllerProvider provider) { m_textView = textView; m_subjectBuffers = subjectBuffers; m_provider = provider; m_textView.MouseHover += this.OnTextViewMouseHover; }
Friend Sub New(ByVal textView As ITextView, ByVal subjectBuffers As IList(Of ITextBuffer), ByVal provider As TestQuickInfoControllerProvider) m_textView = textView m_subjectBuffers = subjectBuffers m_provider = provider AddHandler m_textView.MouseHover, AddressOf Me.OnTextViewMouseHover End Sub
新增觸發程序 QuickInfo 工作階段的滑鼠停留事件處理常式。
private void OnTextViewMouseHover(object sender, MouseHoverEventArgs e) { //find the mouse position by mapping down to the subject buffer SnapshotPoint? point = m_textView.BufferGraph.MapDownToFirstMatch (new SnapshotPoint(m_textView.TextSnapshot, e.Position), PointTrackingMode.Positive, snapshot => m_subjectBuffers.Contains(snapshot.TextBuffer), PositionAffinity.Predecessor); if (point != null) { ITrackingPoint triggerPoint = point.Value.Snapshot.CreateTrackingPoint(point.Value.Position, PointTrackingMode.Positive); if (!m_provider.QuickInfoBroker.IsQuickInfoActive(m_textView)) { m_session = m_provider.QuickInfoBroker.TriggerQuickInfo(m_textView, triggerPoint, true); } } }
Private Sub OnTextViewMouseHover(ByVal sender As Object, ByVal e As MouseHoverEventArgs) 'find the mouse position by mapping down to the subject buffer Dim point As System.Nullable(Of SnapshotPoint) = m_textView.BufferGraph.MapDownToFirstMatch(New SnapshotPoint(m_textView.TextSnapshot, e.Position), PointTrackingMode.Positive, Function(snapshot) m_subjectBuffers.Contains(snapshot.TextBuffer), PositionAffinity.Predecessor) If point IsNot Nothing Then Dim triggerPoint As ITrackingPoint = point.Value.Snapshot.CreateTrackingPoint(point.Value.Position, PointTrackingMode.Positive) If Not m_provider.QuickInfoBroker.IsQuickInfoActive(m_textView) Then m_session = m_provider.QuickInfoBroker.TriggerQuickInfo(m_textView, triggerPoint, True) End If End If End Sub
實作卸離方法,使它當控制器中斷連結的文字檢視時,請移除滑鼠停留事件處理常式。
public void Detach(ITextView textView) { if (m_textView == textView) { m_textView.MouseHover -= this.OnTextViewMouseHover; m_textView = null; } }
Public Sub Detach(ByVal textView As ITextView) Implements IIntellisenseController.Detach If m_textView Is textView Then AddHandler m_textView.MouseHover, AddressOf Me.OnTextViewMouseHover m_textView = Nothing End If End Sub
實作ConnectSubjectBuffer方法和DisconnectSubjectBuffer方法,此範例中的空白方法。
public void ConnectSubjectBuffer(ITextBuffer subjectBuffer) { } public void DisconnectSubjectBuffer(ITextBuffer subjectBuffer) { }
Public Sub ConnectSubjectBuffer(ByVal subjectBuffer As ITextBuffer) Implements IIntellisenseController.ConnectSubjectBuffer End Sub Public Sub DisconnectSubjectBuffer(ByVal subjectBuffer As ITextBuffer) Implements IIntellisenseController.DisconnectSubjectBuffer End Sub
實作 QuickInfo 控制器提供者
QuickInfo 控制站的提供者做主要是為了做為 MEF 元件組件來匯出自己並具現化 QuickInfo 控制站。 因為它是 MEF 元件組件時,它可以匯入其他 MEF 元件組件。
若要實作 QuickInfo controller 提供者
宣告類別,名為
TestQuickInfoControllerProvider
實作IIntellisenseControllerProvider,並將它與匯出NameAttribute的 「 工具提示 QuickInfo 控制器 」 及ContentTypeAttribute為 [文字]:[Export(typeof(IIntellisenseControllerProvider))] [Name("ToolTip QuickInfo Controller")] [ContentType("text")] internal class TestQuickInfoControllerProvider : IIntellisenseControllerProvider
<Export(GetType(IIntellisenseControllerProvider))> _ <Name("ToolTip QuickInfo Controller")> _ <ContentType("text")> _ Friend Class TestQuickInfoControllerProvider Implements IIntellisenseControllerProvider
匯入IQuickInfoBroker做為屬性。
[Import] internal IQuickInfoBroker QuickInfoBroker { get; set; }
Private _QuickInfoBroker As IQuickInfoBroker <Import()> _ Friend Property QuickInfoBroker() As IQuickInfoBroker Get Return _QuickInfoBroker End Get Set(ByVal value As IQuickInfoBroker) _QuickInfoBroker = value End Set End Property
實作TryCreateIntellisenseController方法具現化 QuickInfo 控制站。
public IIntellisenseController TryCreateIntellisenseController(ITextView textView, IList<ITextBuffer> subjectBuffers) { return new TestQuickInfoController(textView, subjectBuffers, this); }
Public Function TryCreateIntellisenseController(ByVal textView As ITextView, ByVal subjectBuffers As IList(Of ITextBuffer)) As IIntellisenseController Implements IIntellisenseControllerProvider.TryCreateIntellisenseController Return New TestQuickInfoController(textView, subjectBuffers, Me) End Function
建置和測試程式碼
若要測試這段程式碼,QuickInfoTest 方案中建置並執行它的實驗執行個體。
若要建置和測試 QuickInfoTest 方案
建置方案。
當您在偵錯工具中執行這個專案時,會具現化第二個 Visual Studio 執行個體。
建立文字檔並輸入一些文字,其中包含單字 「 加入 」 和 「 減去 」。
將指標放在一個 「 加入 」 的項目。 簽章和描述
add
方法應該會顯示。