Compartilhar via


Passo a passo: Exibir dicas de ferramentas de InformaçãoRápida

InformaçãoRápida é um recurso de IntelliSense que exibe as assinaturas de método e descrições quando um usuário move o ponteiro sobre um nome de método. Você pode implementar recursos com base no idioma como, por exemplo, InformaçãoRápida, definindo os identificadores para o qual você deseja fornecer descrições de InformaçãoRápida e, em seguida, criar uma dica de ferramenta para exibir o conteúdo. Você pode definir o InformaçãoRápida no contexto de um serviço de linguagem, você pode definir seu próprio tipo de conteúdo e a extensão de nome do arquivo e exibir a InformaçãoRápida apenas desse tipo ou você pode exibir InformaçãoRápida para um tipo de conteúdo existente (como "texto"). Esta explicação passo a passo mostra como exibir o InformaçãoRápida para o tipo de conteúdo "text".

O exemplo de InformaçãoRápida nesta explicação exibe as dicas de ferramentas quando um usuário move o ponteiro sobre um nome de método. Esse design requer que você implementar esses quatro interfaces:

  • interface de origem

  • interface de provedor de origem

  • interface do controlador

  • interface do provedor controlador

Os provedores de origem e o controlador são partes do componente Managed Extensibility Framework (MEF) e serão responsáveis pela exportação de classes de origem e o controlador e importação de serviços e agentes, como o ITextBufferFactoryService, que cria o buffer de texto de dica de ferramenta e o IQuickInfoBroker, que dispara a sessão de InformaçãoRápida.

Neste exemplo, a fonte de InformaçãoRápida usa uma lista codificada de descrições e nomes de método, mas em implementações completas, o serviço de linguagem e a documentação da linguagem serão responsáveis por fornecer o conteúdo.

Pré-requisitos

Para concluir este passo a passo, você deve instalar o SDL do Visual Studio 2010.

Dica

Para obter mais informações sobre o SDK de Visual Studio, consulte Ampliando a visão geral de Visual Studio.Para descobrir como fazer o download do SDK do Visual Studio, consulte Visual Studio extensibilidade Developer Center no site do MSDN.

Criando um projeto MEF

Para criar um projeto MEF

  1. Crie um projeto do classificador de Editor. Nomeie a solução QuickInfoTest.

  2. Abra o arquivo de Source.extension.vsixmanifest no Editor de VSIX de manifesto.

  3. Certifique-se de que o Content título contém um tipo de conteúdo do componente MEF e que o Path for definido como QuickInfoTest.dll.

  4. Salve e feche o Source.extension.vsixmanifest.

  5. Adicione a seguinte referência ao projeto e defina CopyLocal para false:

    Microsoft.VisualStudio.Language.IntelliSense

  6. Exclua os arquivos de classe existentes.

Implementando a fonte de InformaçãoRápida

A fonte de InformaçãoRápida é responsável por coletar o conjunto de identificadores e suas descrições e adicionando o conteúdo para o buffer de texto de dica de ferramenta quando um dos identificadores é encontrado. Neste exemplo, os identificadores e suas descrições são adicionadas apenas no construtor de código-fonte.

Para implementar a fonte de InformaçãoRápida

  1. Adicione um arquivo de classe e denomine- TestQuickInfoSource.

  2. Adicione as importações a seguintes.

    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;
    
  3. Declara uma classe que implementa IQuickInfoSourcee o nome de TestQuickInfoSource.

    Friend Class TestQuickInfoSource
        Implements IQuickInfoSource
    
    internal class TestQuickInfoSource : IQuickInfoSource
    
  4. Adicione campos para o provedor de origem InformaçãoRápida, o buffer de texto e um conjunto de nomes de métodos e assinaturas de método. Neste exemplo, os nomes de método e as assinaturas são inicializadas na TestQuickInfoSource construtor.

    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;
    
  5. Adicione um construtor que define o provedor de origem InformaçãoRápida e o buffer de texto e preenche o conjunto de nomes de método e assinaturas de método e descrições.

    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.");
    }
    
  6. Implemente o método AugmentQuickInfoSession. Neste exemplo, o método localiza a palavra atual ou a palavra anterior, se o cursor estiver no final de uma linha ou de um buffer de texto. Se a palavra é um dos nomes de método, a descrição para o nome do método é adicionada para o conteúdo de InformaçãoRápida.

    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;
    }
    
  7. Você também deve implementar um método Dispose (), desde então IQuickInfoSource implementa 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;
        }
    }
    

Implementando um provedor de origem do InformaçãoRápida

O provedor de origem InformaçãoRápida serve principalmente para exportar si como uma parte de componente MEF e instanciar a fonte InformaçãoRápida. Porque é uma parte de componente MEF, ele pode importar outras partes do componente MEF.

Para implementar um provedor de origem do InformaçãoRápida

  1. Declara um provedor de origem InformaçãoRápida chamado TestQuickInfoSourceProvider que implementa IQuickInfoSourceProvidere exportá-lo com um NameAttribute de "Origem" da InformaçãoRápida dica de ferramenta, um OrderAttribute de antes de = "default" e um ContentTypeAttribute de "text".

    <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
    
  2. Importar dois serviços do editor, ITextStructureNavigatorSelectorService e ITextBufferFactoryService, como propriedades de 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; }
    
  3. Implementar TryCreateQuickInfoSource para retornar um novo 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);
    }
    

A implementação de um controlador de InformaçãoRápida

Controladores de InformaçãoRápida determinam quando o InformaçãoRápida deve ser exibida. Neste exemplo, InformaçãoRápida é exibida quando o ponteiro está sobre uma palavra que corresponde a um dos nomes de método. O controlador InformaçãoRápida implementa um manipulador de eventos do mouse em foco que aciona uma sessão de InformaçãoRápida.

Para implementar um controlador de InformaçãoRápida

  1. Declara uma classe que implementa IIntellisenseControllere o nome de TestQuickInfoController.

    Friend Class TestQuickInfoController
        Implements IIntellisenseController
    
    internal class TestQuickInfoController : IIntellisenseController
    
  2. Adicione campos privados para o modo de texto, os buffers de texto representados no provedor controlador InformaçãoRápida, a sessão de InformaçãoRápida e o modo de exibição de texto.

    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;
    
  3. Adicione um construtor que define os campos e adiciona o manipulador de eventos do mouse em foco.

    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;
    }
    
  4. Adicione o manipulador de eventos do mouse em foco que dispara a sessão de InformaçãoRápida.

    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);
            }
        }
    }
    
  5. Implementar a Detach método, de modo que ele remove o manipulador de eventos do mouse em foco quando o controlador é desanexado do modo de exibição de texto.

    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;
        }
    }
    
  6. Implementar a ConnectSubjectBuffer método e a DisconnectSubjectBuffer o método como métodos vazios para esse exemplo.

    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)
    {
    }
    

Implementando o provedor controlador InformaçãoRápida

O provedor do controlador InformaçãoRápida serve principalmente para exportar si como uma parte de componente MEF e instanciar o controlador de InformaçãoRápida. Porque é uma parte de componente MEF, ele pode importar outras partes do componente MEF.

Para implementar o provedor de controlador de InformaçãoRápida

  1. Declara uma classe chamada TestQuickInfoControllerProvider que implementa IIntellisenseControllerProvidere exportá-lo com um NameAttribute de "Dica de ferramenta controlador de InformaçãoRápida" e um ContentTypeAttribute de "texto":

    <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
    
  2. Importação de IQuickInfoBroker como uma propriedade.

    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; }
    
  3. Implementar a TryCreateIntellisenseController método instanciando o controlador de InformaçãoRápida.

    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);
    }
    

Criar e testar o código

Para testar esse código, crie a solução de QuickInfoTest e execute-o na instância experimental.

Para criar e testar a solução de QuickInfoTest

  1. Crie a solução.

  2. Ao executar este projeto no depurador, uma segunda instância do Visual Studio é instanciada.

  3. Crie um arquivo de texto e de tipo algum texto que inclui as palavras "Adicionar" e "subtract".

  4. Mova o ponteiro sobre uma das ocorrências de "Adicionar". A assinatura e a descrição da add método deve ser exibido.

Consulte também

Tarefas

Passo a passo: Vinculação a um tipo de conteúdo a uma extensão de nome de arquivo