共用方式為


逐步解說︰ 顯示 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 專案

  1. 建立 C# VSIX 專案。 (在新的專案對話方塊中,選取Visual C# / 擴充性,然後VSIX 專案。)將方案命名為QuickInfoTest

  2. 將編輯器分類項目範本加入至專案。 如需詳細資訊,請參閱編輯器項目範本以建立副檔名為

  3. 刪除現有類別檔案。

實作 QuickInfo 來源

QuickInfo 來源負責收集一組識別項和其描述和內容加入工具提示文字緩衝區時遇到的其中一個識別碼。 在此範例中,識別項和其說明剛加入來源建構函式。

若要實作 QuickInfo 來源

  1. 將類別檔案,並將它TestQuickInfoSource

  2. 加入 Microsoft.VisualStudio.Language.IntelliSense 的參考。

  3. 新增下列匯入。

    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
    
  4. 宣告類別可實作IQuickInfoSource,並將其命名TestQuickInfoSource

    internal class TestQuickInfoSource : IQuickInfoSource
    
    Friend Class TestQuickInfoSource
        Implements IQuickInfoSource
    
  5. 將欄位加入 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)
    
  6. 新增的建構函式設定 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
    
  7. 實作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
    
  8. 您必須也實作 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 來源提供者

  1. 宣告名為 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
    
  2. 匯入兩個編輯器服務, ITextStructureNavigatorSelectorServiceITextBufferFactoryService,以做為屬性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
    
  3. 實作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 控制器

  1. 宣告類別可實作IIntellisenseController,並將其命名TestQuickInfoController

    internal class TestQuickInfoController : IIntellisenseController
    
    Friend Class TestQuickInfoController
        Implements IIntellisenseController
    
  2. 加入私用欄位的 [文字] 檢視中,以表示文字檢視、 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
    
  3. 新增設定欄位並將滑鼠停留事件處理常式的建構函式。

        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
    
  4. 新增觸發程序 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
    
  5. 實作卸離方法,使它當控制器中斷連結的文字檢視時,請移除滑鼠停留事件處理常式。

        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
    
  6. 實作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 提供者

  1. 宣告類別,名為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
    
  2. 匯入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
    
  3. 實作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 方案

  1. 建置方案。

  2. 當您在偵錯工具中執行這個專案時,會具現化第二個 Visual Studio 執行個體。

  3. 建立文字檔並輸入一些文字,其中包含單字 「 加入 」 和 「 減去 」。

  4. 將指標放在一個 「 加入 」 的項目。 簽章和描述add方法應該會顯示。

另請參閱

逐步解說︰ 將內容類型連結至檔案名稱副檔名