QuickInfo 是一種 IntelliSense 功能,當使用者將指標移至方法名稱上方時,會顯示方法簽章和描述。 透過定義要為其提供 QuickInfo 描述的識別馬,然後建立用於顯示內容的工具提示,可以實作以語言為基礎的功能 (例如 QuickInfo)。 您可以在語言服務的內容中定義 QuickInfo,也可以定義自己的副檔名和內容類型,並只顯示該類型的 QuickInfo,也可以顯示現有內容類型的 QuickInfo (例如「文字」)。 本逐步解說示範如何顯示「text」內容類型的 QuickInfo。
本逐步解說中的 QuickInfo 範例,會在使用者將指標移至方法名稱上方時顯示工具提示。 此設計需要您實作這四個介面:
來源介面
來源提供者介面
控制器介面
控制器提供者介面
來源和控制器提供者是 Managed Extensibility Framework (MEF) 元件部分件,負責匯出來源和控制器類別,以及匯入服務與訊息代理程式,例如 ITextBufferFactoryService,它會建立工具提示文字緩衝區,以及 IQuickInfoBroker,它會觸發 QuickInfo 工作階段。
在此範例中,QuickInfo 來源使用方法名稱和描述的硬式編碼清單,但在完整實作中,語言服務和語言文件要負責提供該內容。
建立 MEF 專案
建立 MEF 專案
建立 C# VXIS 專案。 (在新增專案對話框中,選取 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 來源提供者
宣告實作 IQuickInfoSourceProvider,名為 TestQuickInfoSourceProvider 的 QuickInfo 來源提供者,並使用 “ToolTip QuickInfo Source” 的 NameAttribute、Before=“default” 的 OrderAttribute,和 “text” 的 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 控制器提供者新增私用欄位。
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
實作 Detach 方法,以便在控制器與文字檢視中斷連結時,移除滑鼠暫留事件處理常式。
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 控制器提供者
宣告實作 IIntellisenseControllerProvider,名為 TestQuickInfoControllerProvider 的類別,並以 “ToolTip QuickInfo Controller” 的 NameAttribute 和 “text” 的 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
藉由具現化 QuickInfo 控制器來實作 TryCreateIntellisenseController 方法。
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" 和 "subtract" 單字的文字。
將指標移至其中一個出現的 "add"。 應該顯示 add 方法的簽章和描述。
相關內容