Compartilhar via


Passo a passo: Exibindo SmartTags

As marcas inteligentes são marcas de formatação no texto que se expandem para exibir um conjunto de ações. Por exemplo, em um projeto de Visual Basic ou C# Visual, aparece uma linha vermelha sob uma palavra quando você renomeia um identificador como, por exemplo, um nome de variável. Quando você move o ponteiro sobre o sublinhado, um botão é exibido próximo o ponteiro. Se você clicar no botão, uma ação sugerida é exibida, por exemplo, Foi lido de renomear para IsReady. Se você clicar na ação, todas as referências a foi lido no projeto são renomeadas IsReady.

Embora as marcas inteligentes fazem parte da implementação do IntelliSense no editor, você pode implementar as marcas inteligentes, subclassificação SmartTage implementar a ITagger interface e o IViewTaggerProvider interface.

Dica

Outros tipos de marcas podem ser implementados de maneira semelhante.

A instrução a seguir mostra como criar uma marca inteligente que aparece na palavra atual e tem duas ações sugeridas: Converter para maiúsculas e Converter para minúsculas.

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 do Framework (MEF) de extensibilidade gerenciada

Para criar um projeto MEF

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

  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 SmartTagTest.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 um Tagger de marcas inteligentes

Para implementar um tagger de marcas inteligentes

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

  2. Adicione as importações do seguintes:

    Imports System
    Imports System.Collections.Generic
    Imports System.ComponentModel.Composition
    Imports System.Collections.ObjectModel
    Imports System.Windows.Media
    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.ComponentModel.Composition;
    using System.Collections.ObjectModel;
    using System.Windows.Media;
    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. Adicionar uma classe chamada TestSmartTag que herda de SmartTag.

    Friend Class TestSmartTag
        Inherits SmartTag
    
    internal class TestSmartTag : SmartTag
    
  4. Adicionar um construtor para essa classe que chama o construtor base com um SmartTagType de Factoid, que fará com que uma linha azul apareça sob o primeiro caractere de uma palavra. (Se você usar Ephemeral, uma linha vermelha aparecerá abaixo do último caractere da palavra.)

    Public Sub New(ByVal actionSets As ReadOnlyCollection(Of SmartTagActionSet))
        MyBase.New(SmartTagType.Factoid, actionSets)
    End Sub
    
    public TestSmartTag(ReadOnlyCollection<SmartTagActionSet> actionSets) :
        base(SmartTagType.Factoid, actionSets) { }
    
  5. Adicionar uma classe chamada TestSmartTagger que herda de ITagger do tipo TestSmartTage implementa IDisposable.

    Friend Class TestSmartTagger
        Implements ITagger(Of TestSmartTag), IDisposable
    
    internal class TestSmartTagger : ITagger<TestSmartTag>, IDisposable
    
  6. Adicione os seguintes campos particulares à classe tagger.

    Private m_buffer As ITextBuffer
    Private m_view As ITextView
    Private m_provider As TestSmartTaggerProvider
    Private m_disposed As Boolean
    
    private ITextBuffer m_buffer;
    private ITextView m_view;
    private TestSmartTaggerProvider m_provider;
    private bool m_disposed;
    
  7. Adicionar um construtor que define os campos particulares e assina o LayoutChanged evento.

    Public Sub New(ByVal buffer As ITextBuffer, ByVal view As ITextView, ByVal provider As TestSmartTaggerProvider)
        m_buffer = buffer
        m_view = view
        m_provider = provider
        AddHandler m_view.LayoutChanged, AddressOf OnLayoutChanged
    End Sub
    
    public TestSmartTagger(ITextBuffer buffer, ITextView view, TestSmartTaggerProvider provider)
    {
        m_buffer = buffer;
        m_view = view;
        m_provider = provider;
        m_view.LayoutChanged += OnLayoutChanged;
    }
    
  8. Implementar GetTags para que a marca é criada para a palavra atual. (Esse método também chama um método particular GetSmartTagActions que é explicado posteriormente.)

    Public Function GetTags(ByVal spans As NormalizedSnapshotSpanCollection) As IEnumerable(Of ITagSpan(Of TestSmartTag)) Implements ITagger(Of TestSmartTag).GetTags
        Dim snapshot As ITextSnapshot = m_buffer.CurrentSnapshot
        If snapshot.Length = 0 Then 
            Return Nothing 
            Exit Function 
        End If 
    
        'set up the navigator 
        Dim navigator As ITextStructureNavigator = m_provider.NavigatorService.GetTextStructureNavigator(m_buffer)
    
        'set up a list to contain the tags 
        Dim list As List(Of TagSpan(Of TestSmartTag))
        list = New List(Of TagSpan(Of TestSmartTag))()
    
        For Each span In spans
            Dim caret As ITextCaret = m_view.Caret
            Dim point As SnapshotPoint
    
            If CInt(caret.Position.BufferPosition) > 0 Then
                point = caret.Position.BufferPosition - 1
            Else 
                Exit For 
            End If 
    
            Dim extent As TextExtent = navigator.GetExtentOfWord(point)
            'don't display the tag if the extent has whitespace 
            If extent.IsSignificant Then
                list.Add(New TagSpan(Of TestSmartTag)(extent.Span, New TestSmartTag(GetSmartTagActions(extent.Span))))
            Else 
                Exit For 
            End If 
        Next span
    
        Return list
    End Function
    
    public IEnumerable<ITagSpan<TestSmartTag>> GetTags(NormalizedSnapshotSpanCollection spans)
    {
        ITextSnapshot snapshot = m_buffer.CurrentSnapshot;
        if (snapshot.Length == 0)
            yield break; //don't do anything if the buffer is empty 
    
        //set up the navigator
        ITextStructureNavigator navigator = m_provider.NavigatorService.GetTextStructureNavigator(m_buffer);
    
        foreach (var span in spans)
        {
            ITextCaret caret = m_view.Caret;
            SnapshotPoint point;
    
            if (caret.Position.BufferPosition > 0)
                point = caret.Position.BufferPosition - 1;
            else 
                yield break;
    
            TextExtent extent = navigator.GetExtentOfWord(point);
            //don't display the tag if the extent has whitespace 
            if (extent.IsSignificant)
                yield return new TagSpan<TestSmartTag>(extent.Span, new TestSmartTag(GetSmartTagActions(extent.Span)));
            else yield break;
        }
    }
    
  9. Adicionar um GetSmartTagActions método para configurar as ações de marca inteligente. As ações propriamente ditas são implementadas em etapas posteriores.

    Private Function GetSmartTagActions(ByVal span As SnapshotSpan) As ReadOnlyCollection(Of SmartTagActionSet)
        Dim actionSetList As New List(Of SmartTagActionSet)()
        Dim actionList As New List(Of ISmartTagAction)()
    
        Dim trackingSpan As ITrackingSpan = span.Snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeInclusive)
        actionList.Add(New UpperCaseSmartTagAction(trackingSpan))
        actionList.Add(New LowerCaseSmartTagAction(trackingSpan))
        Dim actionSet As New SmartTagActionSet(actionList.AsReadOnly())
        actionSetList.Add(actionSet)
        Return actionSetList.AsReadOnly()
    End Function
    
    private ReadOnlyCollection<SmartTagActionSet> GetSmartTagActions(SnapshotSpan span)
    {
        List<SmartTagActionSet> actionSetList = new List<SmartTagActionSet>();
        List<ISmartTagAction> actionList = new List<ISmartTagAction>();
    
        ITrackingSpan trackingSpan = span.Snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeInclusive);
        actionList.Add(new UpperCaseSmartTagAction(trackingSpan));
        actionList.Add(new LowerCaseSmartTagAction(trackingSpan));
        SmartTagActionSet actionSet = new SmartTagActionSet(actionList.AsReadOnly());
        actionSetList.Add(actionSet);
        return actionSetList.AsReadOnly();
    }
    
  10. Declarar o SmartTagsChanged evento.

    Public Event TagsChanged As EventHandler(Of SnapshotSpanEventArgs) Implements ITagger(Of TestSmartTag).TagsChanged
    
    public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
    
  11. Implementar a OnLayoutChanged o manipulador de eventos para elevar a TagsChanged o evento, que faz com que GetTags a ser chamado.

    Private Sub OnLayoutChanged(ByVal sender As Object, ByVal e As TextViewLayoutChangedEventArgs)
        Dim snapshot As ITextSnapshot = e.NewSnapshot
        'don't do anything if this is just a change in case 
        If Not snapshot.GetText().ToLower().Equals(e.OldSnapshot.GetText().ToLower()) Then 
            Dim span As New SnapshotSpan(snapshot, New Span(0, snapshot.Length))
            Dim handler As EventHandler(Of SnapshotSpanEventArgs) = Me.TagsChangedEvent
            If handler IsNot Nothing Then
                handler(Me, New SnapshotSpanEventArgs(span))
            End If 
        End If 
    End Sub
    
    private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
    {
        ITextSnapshot snapshot = e.NewSnapshot;
        //don't do anything if this is just a change in case 
        if (!snapshot.GetText().ToLower().Equals(e.OldSnapshot.GetText().ToLower()))
        {
            SnapshotSpan span = new SnapshotSpan(snapshot, new Span(0, snapshot.Length));
            EventHandler<SnapshotSpanEventArgs> handler = this.TagsChanged;
            if (handler != null)
            {
                handler(this, new SnapshotSpanEventArgs(span));
            }
        }
    }
    
  12. Implementar a Dispose método, de modo que ele cancela a inscrição da LayoutChanged evento.

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub 
    
    Private Sub Dispose(ByVal disposing As Boolean)
        If disposing Then 
            RemoveHandler m_view.LayoutChanged, AddressOf OnLayoutChanged
            m_view = Nothing 
        End If
    
        m_disposed = True 
    End Sub
    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    
    private void Dispose(bool disposing)
    {
        if (!this.m_disposed)
        {
            if (disposing)
            {
                m_view.LayoutChanged -= OnLayoutChanged;
                m_view = null;
            }
    
            m_disposed = true;
        }
    }
    

Implementando o provedor de Tagger de marca inteligente

Para implementar o provedor de tagger de marca inteligente

  1. Adicionar uma classe chamada TestSmartTagTaggerProvider que herda de IViewTaggerProvider. Exportá-lo com um ContentTypeAttribute de "texto", um OrderAttribute de antes de = "default" e um TagTypeAttribute de SmartTag.

    <Export(GetType(IViewTaggerProvider))>
    <ContentType("text")>
    <Order(Before:="default")>
    <TagType(GetType(SmartTag))>
    Friend Class TestSmartTaggerProvider
        Implements IViewTaggerProvider
    
    [Export(typeof(IViewTaggerProvider))]
    [ContentType("text")]
    [Order(Before = "default")]
    [TagType(typeof(SmartTag))]
    internal class TestSmartTaggerProvider : IViewTaggerProvider
    
  2. Importação de ITextStructureNavigatorSelectorService como uma propriedade.

    <Import(GetType(ITextStructureNavigatorSelectorService))>
    Friend Property NavigatorService() As ITextStructureNavigatorSelectorService
    
    [Import(typeof(ITextStructureNavigatorSelectorService))]
    internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
    
  3. Implemente o método CreateTagger``1.

    Public Function CreateTagger(Of T As ITag)(ByVal textView As ITextView, ByVal buffer As ITextBuffer) As ITagger(Of T) Implements IViewTaggerProvider.CreateTagger
        If buffer Is Nothing OrElse textView Is Nothing Then 
            Return Nothing 
        End If 
    
        'make sure we are tagging only the top buffer 
        If buffer Is textView.TextBuffer Then 
            Return New TestSmartTagger(buffer, textView, Me)
        Else 
            Return Nothing 
        End If 
    End Function
    
    public ITagger<T> CreateTagger<T>(ITextView textView, ITextBuffer buffer) where T : ITag
    {
        if (buffer == null || textView == null)
        {
            return null;
        }
    
        //make sure we are tagging only the top buffer 
        if (buffer == textView.TextBuffer)
        {
            return new TestSmartTagger(buffer, textView, this) as ITagger<T>;
        }
        else return null;
    }
    

A implementação de ações com marcas inteligentes

Para implementar as ações de marca inteligente

  • Criar duas classes, a primeira chamada UpperCaseSmartTagAction e a segunda chamada LowerCaseSmartTagAction. Ambas as classes que implementam ISmartTagAction.

    Friend Class UpperCaseSmartTagAction
        Implements ISmartTagAction
    
    internal class UpperCaseSmartTagAction : ISmartTagAction
    
    Friend Class LowerCaseSmartTagAction
        Implements ISmartTagAction
    
    internal class LowerCaseSmartTagAction : ISmartTagAction
    

Ambas as classes são iguais, exceto que chama por um ToUpper e as outras chamadas ToLower. As etapas a seguir abrangem somente a classe de ação em maiúsculas, mas você deve implementar ambas as classes. Use as etapas para implementar as ações em maiúsculas como um padrão para implementar a ação de minúsculas.

  1. Declare um conjunto de campos particulares.

    Private m_span As ITrackingSpan
    Private m_upper As String 
    Private m_display As String 
    Private m_snapshot As ITextSnapshot
    
    private ITrackingSpan m_span;
    private string m_upper;
    private string m_display;
    private ITextSnapshot m_snapshot;
    
  2. Adicione um construtor que define os campos.

    Public Sub New(ByVal span As ITrackingSpan)
        m_span = span
        m_snapshot = span.TextBuffer.CurrentSnapshot
        m_upper = span.GetText(m_snapshot).ToUpper()
        m_display = "Convert to upper case" 
    End Sub
    
    public UpperCaseSmartTagAction(ITrackingSpan span)
    {
        m_span = span;
        m_snapshot = span.TextBuffer.CurrentSnapshot;
        m_upper = span.GetText(m_snapshot).ToUpper();
        m_display = "Convert to upper case";
    }
    
  3. Implemente as propriedades da seguinte maneira.

    Public ReadOnly Property DisplayText() As String Implements ISmartTagAction.DisplayText
        Get 
            Return m_display
        End Get 
    End Property 
    Public ReadOnly Property Icon() As ImageSource Implements ISmartTagAction.Icon
        Get 
            Return Nothing 
        End Get 
    End Property 
    Public ReadOnly Property IsEnabled() As Boolean Implements ISmartTagAction.IsEnabled
        Get 
            Return True 
        End Get 
    End Property 
    
    Private privateSource As ISmartTagSource
    Public Property Source() As ISmartTagSource
        Get 
            Return privateSource
        End Get 
        Private Set(ByVal value As ISmartTagSource)
            privateSource = value
        End Set 
    End Property 
    
    Public ReadOnly Property ActionSets() As ReadOnlyCollection(Of SmartTagActionSet) Implements ISmartTagAction.ActionSets
        Get 
            Return Nothing 
        End Get 
    End Property
    
    public string DisplayText
    {
        get { return m_display; }
    }
    public ImageSource Icon
    {
        get { return null; }
    }
    public bool IsEnabled
    {
        get { return true; }
    }
    
    public ISmartTagSource Source
    {
        get;
        private set;
    }
    
    public ReadOnlyCollection<SmartTagActionSet> ActionSets
    {
        get { return null; }
    }
    
  4. Implementar a Invoke método, substituindo o texto no trecho com seu equivalente em maiúsculas.

    Public Sub Invoke() Implements ISmartTagAction.Invoke
        m_span.TextBuffer.Replace(m_span.GetSpan(m_snapshot), m_upper)
    End Sub
    
    public void Invoke()
    {
        m_span.TextBuffer.Replace(m_span.GetSpan(m_snapshot), m_upper);
    }
    

Criar e testar o código

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

Para criar e testar a solução de SmartTagTest

  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 digite algum texto.

    Uma linha azul deve ser exibida sob a primeira letra da primeira palavra do texto.

  4. Mova o ponteiro sobre a linha azul.

    Um botão deve ser exibido perto do ponteiro.

  5. Quando você clica no botão, dois sugeridas ações devem ser exibidas: Converter para maiúsculas e Converter para minúsculas. Se você clicar a primeira ação, todo o texto na palavra atual que deve ser convertido em maiúsculas. Se você clicar a segunda ação, todo o texto deve ser convertido para minúsculas.

Consulte também

Tarefas

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