QuickInfo 是一项 IntelliSense 功能,当用户将指针移到方法名称上时显示方法签名和说明。 可以通过定义要为其提供 QuickInfo 说明的标识符,然后创建一个用于显示内容的工具提示来实现基于语言的功能,例如 QuickInfo。 可以在语言服务的上下文中定义 QuickInfo,也可以定义自己的文件扩展名和内容类型,并仅显示该类型的 QuickInfo,也可以为现有内容类型(如“text”)显示 QuickInfo。 本演练演示如何显示“text”内容类型的 QuickInfo。
本演练中的 QuickInfo 示例显示当用户将指针移到方法名称上时的工具提示。 此设计要求你实现以下四个接口:
创建 MEF 项目
创建 MEF 项目
创建 C# VSIX 项目。 (在 “新建项目 ”对话框,选择 Visual C# /扩展性,然后选择 VSIX Project。)将解决方案 QuickInfoTest
命名为 。
向项目添加编辑器分类器项模板。 有关详细信息,请参阅使用编辑器项模板创建扩展。
删除现有的类文件。
实现 QuickInfo 源
QuickInfo 源负责收集标识符集及其说明,并在遇到其中一个标识符时将内容添加到工具提示文本缓冲区。 在此示例中,标识符及其说明刚刚添加到源构造函数中。
实现 QuickInfo 源
添加一个类文件并将其命名为 TestQuickInfoSource
。
添加对 Microsoft.VisualStudio.Language.IntelliSense 的引用。
添加以下 import 语句。
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 源提供程序
声明名为TestQuickInfoSourceProvider
实现的 IQuickInfoSourceProviderQuickInfo 源提供程序,并使用“ToolTip QuickInfo Source”、“Before=”default“OrderAttribute和ContentTypeAttribute”text“导出它NameAttribute。
[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 控制器提供程序
声明一个名为TestQuickInfoControllerProvider
实现IIntellisenseControllerProvider的类,并使用“ToolTip QuickInfo Controller”和ContentTypeAttribute“text”导出它NameAttribute:
[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”和“subtract”的文本。
将指针移到“add”的其中一个匹配项上。 应显示方法的 add
签名和说明。
相关内容