以前是公开方法签名和说明的 IntelliSense 功能,当用户将方法名称时的指针。 通过定义要提供以前声明的标识符,然后创建显示的内容的工具提示实现的语言为基础的功能 (如以前。 可以定义快速信息在语言服务中,也可以定义拥有文件扩展名与内容类型并显示该类型的快速信息,也可以显示现有内容类型的快速信息 (例如 “text”)。 本演练演示了如何显示 “文本”内容类型的快速信息。
,当用户将方法名称时,的指针在本演练中的以前的示例显示工具提示。 此模型要求您实现这四个接口:
源接口
源提供程序接口
管理员接口
管理员提供程序接口
源和管理员提供程序是托管扩展性框架 (MEF)组成部分,并对导出源和控制器类和导入服务和代理负责例如 ITextBufferFactoryService,创建工具提示文本缓冲区和 IQuickInfoBroker,触发快速信息会话。
在此示例中,以前的源使用硬编码列表方法名称和说明,但是,在完整的实现,语言服务和语言文档负责提供该目录。
系统必备
若要完成本演练,您必须安装 Visual Studio 2010 SDK。
备注
有关 Visual Studio SDK 的更多信息,请参见 扩展 Visual Studio 概述。若要查找有关中所列如何下载 Visual Studio SDK,请 Visual Studio Extensibility Developer Center 参见 MSDN 网站上。
创建 MEF 项目
创建 MEF 项目
创建一个编辑分类器项目。 将解决方案命名为 QuickInfoTest。
打开在 VSIX 清单编辑器中的 Source.extension.vsixmanifest 文件。
确保 Content 归为包含一个 MEF 组件内容类型,而 Path 设置为 QuickInfoTest.dll。
保存并关闭的 Source.extension.vsixmanifest。
将下列引用添加到项目,并将 CopyLocal 到 false:
Microsoft.VisualStudio.Language.Intellisense
删除现有类文件。
实现快速信息源
,在一个标识符遇到时,以前的源为集合设置标识符及其说明和添加内容负责向工具提示文本缓冲区。 在本示例中,标识符及其说明在源构造函数添加。
实现快速信息源
将类文件并将其命名为 TestQuickInfoSource。
添加下面的导入。
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
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;
声明实现 IQuickInfoSource的类,并将其命名为 TestQuickInfoSource。
Friend Class TestQuickInfoSource Implements IQuickInfoSource
internal class TestQuickInfoSource : IQuickInfoSource
添加以前的源提供程序,文本缓冲区和的字段设置方法名称和方法签名。 在此示例中,方法名称和签名。 TestQuickInfoSource 构造函数初始化。
Private m_provider As TestQuickInfoSourceProvider Private m_subjectBuffer As ITextBuffer Private m_dictionary As Dictionary(Of String, String)
private TestQuickInfoSourceProvider m_provider; private ITextBuffer m_subjectBuffer; private Dictionary<string, string> m_dictionary;
添加设置以前的源提供程序和文本缓冲区的构造函数,然后填入设置方法名称和方法签名和说明。
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
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."); }
实现 AugmentQuickInfoSession 方法。 在此示例中,因此,如果光标位于行或文本缓冲区的末尾,方法查找当前字或前一个单词。 如果该单词是一个方案名称,该方法名称的声明添加到快速信息内容。
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) 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
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 ); string value; m_dictionary.TryGetValue(key, out value); if (value != null) qiContent.Add(value); else qiContent.Add(""); return; } } applicableToSpan = null; }
还必须执行一个 Dispose() 方法,从 IQuickInfoSource 实现 IDisposable:
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
private bool m_isDisposed; public void Dispose() { if (!m_isDisposed) { GC.SuppressFinalize(this); m_isDisposed = true; } }
实现快速信息提供程序源
以前的源的提供程序主要服务自身为 MEF 组件部件和实例化以前的源。 由于它是 MEF 组件部件,它可以导入其他 MEF 组件。
实现快速信息提供程序源
声明实现 IQuickInfoSourceProvider的快速信息提供程序源名为 TestQuickInfoSourceProvider ,并将其导出与 “工具提示以前的源” NameAttribute , OrderAttribute Before= " default”和 “text” ContentTypeAttribute 。
<Export(GetType(IQuickInfoSourceProvider))> _ <Name("ToolTip QuickInfo Source")> _ <Order(Before:=" Default Quick Info Presenter")> _ <ContentType("text")> _ Friend Class TestQuickInfoSourceProvider Implements IQuickInfoSourceProvider
[Export(typeof(IQuickInfoSourceProvider))] [Name("ToolTip QuickInfo Source")] [Order(Before = "Default Quick Info Presenter")] [ContentType("text")] internal class TestQuickInfoSourceProvider : IQuickInfoSourceProvider
导入两个编辑服务, ITextStructureNavigatorSelectorService 和 ITextBufferFactoryService,作为 TestQuickInfoSourceProvider属性。
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
[Import] internal ITextStructureNavigatorSelectorService NavigatorService { get; set; } [Import] internal ITextBufferFactoryService TextBufferFactoryService { get; set; }
实现 TryCreateQuickInfoSource 返回新的 TestQuickInfoSource。
Public Function TryCreateQuickInfoSource(ByVal textBuffer As ITextBuffer) As IQuickInfoSource Implements IQuickInfoSourceProvider.TryCreateQuickInfoSource Return New TestQuickInfoSource(Me, textBuffer) End Function
public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer) { return new TestQuickInfoSource(this, textBuffer); }
实现快速信息控制器
以前的管理员确定何时显示快速信息。 在此示例中,以前显示,当指针在相应某个方法名称的模式。 以前的管理员实现触发快速信息会话中的鼠标悬停事件处理程序。
实现快速信息控制器
声明实现 IIntellisenseController的类,并将其命名为 TestQuickInfoController。
Friend Class TestQuickInfoController Implements IIntellisenseController
internal class TestQuickInfoController : IIntellisenseController
添加文本视图、在文本视图显示的文本缓冲区,快速信息会话和以前的管理员提供程序的私有字段。
Private m_textView As ITextView Private m_subjectBuffers As IList(Of ITextBuffer) Private m_provider As TestQuickInfoControllerProvider Private m_session As IQuickInfoSession
private ITextView m_textView; private IList<ITextBuffer> m_subjectBuffers; private TestQuickInfoControllerProvider m_provider; private IQuickInfoSession m_session;
将设置添加字段并添加鼠标悬停事件处理程序的构造函数。
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
internal TestQuickInfoController(ITextView textView, IList<ITextBuffer> subjectBuffers, TestQuickInfoControllerProvider provider) { m_textView = textView; m_subjectBuffers = subjectBuffers; m_provider = provider; m_textView.MouseHover += this.OnTextViewMouseHover; }
添加触发快速信息会话的鼠标悬停事件处理程序。
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
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); } } }
执行 Detach 方法,使其移除鼠标悬停事件处理程序,当该控制器从文本视图时分离。
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
public void Detach(ITextView textView) { if (m_textView == textView) { m_textView.MouseHover -= this.OnTextViewMouseHover; m_textView = null; } }
执行 ConnectSubjectBuffer 方法和 DisconnectSubjectBuffer 方法是此示例的空方法。
Public Sub ConnectSubjectBuffer(ByVal subjectBuffer As ITextBuffer) Implements IIntellisenseController.ConnectSubjectBuffer End Sub Public Sub DisconnectSubjectBuffer(ByVal subjectBuffer As ITextBuffer) Implements IIntellisenseController.DisconnectSubjectBuffer End Sub
public void ConnectSubjectBuffer(ITextBuffer subjectBuffer) { } public void DisconnectSubjectBuffer(ITextBuffer subjectBuffer) { }
实现快速信息提供程序控制器
以前控制器的提供程序主要服务自身为 MEF 组件部件和实例化以前的控制器。 由于它是 MEF 组件部件,它可以导入其他 MEF 组件。
实现快速信息提供程序控制器
声明实现 IIntellisenseControllerProvider的类名为 TestQuickInfoControllerProvider ,并将其导出与 “工具提示以前的管理员” NameAttribute 和 “text” ContentTypeAttribute :
<Export(GetType(IIntellisenseControllerProvider))> _ <Name("ToolTip QuickInfo Controller")> _ <ContentType("text")> _ Friend Class TestQuickInfoControllerProvider Implements IIntellisenseControllerProvider
[Export(typeof(IIntellisenseControllerProvider))] [Name("ToolTip QuickInfo Controller")] [ContentType("text")] internal class TestQuickInfoControllerProvider : IIntellisenseControllerProvider
导入 IQuickInfoBroker 为特性。
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
[Import] internal IQuickInfoBroker QuickInfoBroker { get; set; }
通过实例化以前的管理员执行 TryCreateIntellisenseController 方法。
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
public IIntellisenseController TryCreateIntellisenseController(ITextView textView, IList<ITextBuffer> subjectBuffers) { return new TestQuickInfoController(textView, subjectBuffers, this); }
生成并测试代码
若要测试此代码,请生成 QuickInfoTest 解决方案并运行在的实验实例。
生成和测试 QuickInfoTest 解决方案
生成解决方案。
当您运行在调试器中查看此项目, Visual Studio 的第二个实例进行实例化。
创建一个文本文件并键入中包含单词 “添加”, “中减去”的某些文本。
将指针一次出现 “添加”。 应显示签名和 add 方法的说明。