Partager via


Procédure pas - à - pas : afficher SmartTags

Les balises actives sont des indicateurs sur le texte qui s'agrandissent pour afficher un jeu d'actions. Par exemple, dans un projet Visual Basic ou Visual c#, une ligne rouge apparaît sous un mot lorsque vous renommez un identificateur comme un nom de variable. Lorsque vous déplacez le pointeur sur le soulignement, un bouton apparaît près de le pointeur. Si vous cliquez sur le bouton, une action suggérée s'affiche, par exemple, renommez IsRead à IsReady. si vous cliquez sur l'action, toutes les références à IsRead dans le projet sont renommées IsReady.

Bien que les balises actives fassent partie de l'implémentation d'Intellisense dans l'éditeur, vous pouvez implémenter des balises actives par sous-classement SmartTag, puis implémenter l'interface de ITagger et l'interface d' IViewTaggerProvider .

Notes

D'autres types de balises peuvent être implémentés de la même manière.

La procédure pas - à - pas suivante montre comment créer une balise active qui s'affiche sur le mot actuel et a deux actions suggérées : Converti en majuscules et Converti en minuscules.

Composants requis

Pour exécuter cette procédure, vous devez installer Kit de développement logiciel Visual Studio 2010.

Notes

Pour plus d'informations sur le kit de développement Visual Studio, consultez Étendre la présentation de Visual Studio.Pour savoir comment télécharger le kit de développement Visual Studio, consultez Visual Studio Extensibility Developer Center sur le site Web MSDN.

Créer un projet managé (MEF) managed extensibility framework

Pour créer un projet MEF

  1. Créez un projet de classifieur d'éditeur. nommez la solution SmartTagTest.

  2. Ouvrez le fichier source.extension.vsixmanifest dans l'éditeur de manifeste VSIX.

  3. Assurez -vous que le titre d' Content contient un type de contenu composant MEF et qu' Path est défini à SmartTagTest.dll.

  4. Enregistrez et fermez le fichier source.extension.vsixmanifest.

  5. ajoutez la référence suivante au projet, et CopyLocal défini à false:

    Microsoft.VisualStudio.Language.Intellisense

  6. supprimez les fichiers de classe existants.

Implémenter un balises pour les balises actives

Pour implémenter un balises pour les balises actives

  1. ajoutez un fichier de classe et nommez-le TestSmartTag.

  2. Ajoutez les importations ci-après :

    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. ajoutez une classe nommée TestSmartTag qui hérite d' SmartTag.

    Friend Class TestSmartTag
        Inherits SmartTag
    
    internal class TestSmartTag : SmartTag
    
  4. Ajoutez un constructeur pour cette classe qui appelle le constructeur de base avec SmartTagType d' Factoid, qui entraînera apparaître une ligne bleue sous le premier caractère d'un mot. (Si vous utilisez Ephemeral, une ligne rouge apparaît sous le dernier caractère du mot.)

    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. ajoutez une classe nommée TestSmartTagger qui hérite d' ITagger de type TestSmartTag, et implémentez IDisposable.

    Friend Class TestSmartTagger
        Implements ITagger(Of TestSmartTag), IDisposable
    
    internal class TestSmartTagger : ITagger<TestSmartTag>, IDisposable
    
  6. Ajoutez des champs privés suivants à la classe de balises.

    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. ajoutez un constructeur qui définit les champs privés, et abonnez à LayoutChanged l'événement.

    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. Implémentez l' GetTags afin que la balise soit créé pour le mot actuel. (Cette méthode appelle également une méthode privée GetSmartTagActions qui est expliquée ultérieurement.)

    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. ajoutez une méthode d' GetSmartTagActions pour installer les actions de balise active. Les actions elles-mêmes sont implémentées dans les étapes ultérieures.

    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. déclarez l'événement d' SmartTagsChanged .

    Public Event TagsChanged As EventHandler(Of SnapshotSpanEventArgs) Implements ITagger(Of TestSmartTag).TagsChanged
    
    public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
    
  11. Implémentez le gestionnaire d'événements d' OnLayoutChanged pour déclencher l'événement d' TagsChanged , ce qui provoque l' GetTags à appeler.

    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. Implémentez la méthode d' Dispose afin qu'elle annule un abonnement à l'événement d' LayoutChanged .

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

Implémenter le fournisseur de balises de balise active

Pour implémenter le fournisseur de balises de balise active

  1. ajoutez une classe nommée TestSmartTagTaggerProvider qui hérite d' IViewTaggerProvider. Exportez-la avec ContentTypeAttribute « texte », OrderAttribute de Before= " défaut », et TagTypeAttribute d' 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. Importez ITextStructureNavigatorSelectorService en tant que propriété.

    <Import(GetType(ITextStructureNavigatorSelectorService))>
    Friend Property NavigatorService() As ITextStructureNavigatorSelectorService
    
    [Import(typeof(ITextStructureNavigatorSelectorService))]
    internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
    
  3. Implémentez la méthode 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;
    }
    

L'implémentation des actions de balise active

pour implémenter des actions de balise active

  • créez deux classes, le premier UpperCaseSmartTagAction nommé et le deuxième LowerCaseSmartTagActionnommé. les deux classes implémentent ISmartTagAction.

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

Les deux classes sont identiques sauf qu'il appelle ToUpper et l'autre appelle ToLower. Les étapes suivantes expliquent uniquement la classe majuscule d'action, mais vous devez implémenter les deux classes. Utilisez les étapes nécessaires pour implémenter l'action majuscule comme modèle pour implémenter l'action minuscules.

  1. déclarez un ensemble de champs privés.

    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. ajoutez un constructeur qui définit les champs.

    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. implémentez les propriétés comme suit.

    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. Implémentez la méthode d' Invoke en remplaçant le texte de la plage avec son équivalent de majuscules.

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

Génération et test de code

Pour tester ce code, générez la solution de SmartTagTest et exécutez -la dans l'instance expérimentale.

Pour générer et tester la solution de SmartTagTest

  1. Générez la solution.

  2. Lorsque vous exécutez ce projet dans le débogueur, une deuxième instance de Visual Studio est instanciée.

  3. Créez un fichier texte et tapez du texte.

    Une ligne bleue doit être affichée sous la première lettre du premier mot du texte.

  4. Déplacez le pointeur sur la ligne bleue.

    Un bouton doit être affiché près de le pointeur.

  5. Lorsque vous cliquez sur le bouton, deux actions suggérées doivent apparaître : Convertit en majuscules et Convertit en minuscules. Si vous cliquez sur la première action, tout le texte dans le mot actuel doit être converti en majuscules. Si vous cliquez sur la deuxième action, tout le texte doit être converti en en minuscules.

Voir aussi

Tâches

Procédure pas - à - pas : lier un type de contenu à une extension de nom de fichier