Поделиться через


Пошаговое руководство: отображение смарт-тегов

Смарт-теги теги для текста, разверните для отображения набора действий. Например, в проекте Visual Basic или Visual c#, красная линия отображается под машинное слово при переименовании идентификатора в качестве имени переменной. При перемещении указателя над подчеркиванием, кнопка отображается рядом указателя. При нажатии кнопки отображается предложенная действие, например Переименовать в IsReady IsRead. Если нажать кнопку действие, все ссылки на IsReady IsRead в проекте переименованы.

Хотя смарт-теги часть реализации IntelliSense в редакторе можно реализовать смарт-тегов с subclassing SmartTagи реализация ITagger интерфейс и IViewTaggerProvider интерфейс.

Примечание

Другие типы тегов можно реализовать таким же образом.

В следующем пошаговом руководстве показано, как создать смарт-тег, который появляется на текущее машинное слово и принадлежит 2 предложенных действий: Преобразовать в верхний регистр и Преобразовать в нижний регистр.

Обязательные компоненты

Чтобы выполнить это пошаговое руководство, необходимо устанавливать SDK для Visual Studio 2010.

Примечание

Дополнительные сведения о пакете SDK для Visual Studio см. в разделе интеграция SDK Visual Studio.Чтобы узнать, как загрузить пакет SDK для Visual Studio см. в разделе Центр разработчиков расширяемости Visual Studio на веб-сайте MSDN.

Создание управляемой расширяемости проекта .NET Framework (платформа MEF)

Создание проекта MEF

  1. Создайте проект классификатора редактора. Назовите решение SmartTagTest.

  2. Откройте файл source.extension.vsixmanifest в редакторе манифеста VSIX.

  3. Убедитесь, что Content заголовок содержит тип содержимого и компонент MEF Path имеет значение SmartTagTest.dll.

  4. Сохранить и закрыть source.extension.vsixmanifest.

  5. Добавьте следующую ссылку на проект и набору CopyLocal В false.

    Microsoft.VisualStudio.Language.Intellisense

  6. Удалите существующие файлы классов.

Средство создания тегов для реализации для смарт-тегов

Средство создания тегов для реализации для смарт-тегов

  1. Добавьте файл классов и назовите его TestSmartTag.

  2. Добавьте следующие ввозы:

    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. Добавьте в проект класс TestSmartTag он наследует SmartTag.

    Friend Class TestSmartTag
        Inherits SmartTag
    
    internal class TestSmartTag : SmartTag
    
  4. Добавьте конструктор для данного класса, который вызывает базовый конструктор с a SmartTagTypeFactoid, который приведет к голубую линию появляться под первый символ машинного слова. (При использовании Ephemeral, красная линия отображается под последний знак машинного слова.)

    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. Добавьте в проект класс TestSmartTagger он наследует ITagger type TestSmartTagи реализует IDisposable.

    Friend Class TestSmartTagger
        Implements ITagger(Of TestSmartTag), IDisposable
    
    internal class TestSmartTagger : ITagger<TestSmartTag>, IDisposable
    
  6. Добавьте следующие закрытые поля к классу средство создания тегов для.

    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. Добавьте конструктор, который устанавливает частные поля и подписки LayoutChanged событие.

    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. Реализация GetTags таким образом, что тег будет создан для текущего формирование. (Этот метод также вызывает закрытый метод GetSmartTagActions это описано ниже.)

    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. Add a GetSmartTagActions метод, чтобы настроить действия смарт-тегов. Сами действия выполняются в последующих шагах.

    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. Объявите SmartTagsChanged событие.

    Public Event TagsChanged As EventHandler(Of SnapshotSpanEventArgs) Implements ITagger(Of TestSmartTag).TagsChanged
    
    public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
    
  11. Реализуйте GetTags обработчик для вызова OnLayoutChanged событие, вызывающее TagsChanged вызываться.

    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. Реализуйте Dispose метод, чтобы он unsubscribes из 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;
        }
    }
    

Реализация поставщика средство создания тегов для смарт-тегов

Реализация поставщика средство создания тегов для смарт-тегов

  1. Добавьте в проект класс TestSmartTagTaggerProvider он наследует IViewTaggerProvider. Экспортировать его a ContentTypeAttribute "текст", a OrderAttribute Before= " default" и " a " TagTypeAttributeSmartTag.

    <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. Импортировать ITextStructureNavigatorSelectorService как свойство.

    <Import(GetType(ITextStructureNavigatorSelectorService))>
    Friend Property NavigatorService() As ITextStructureNavigatorSelectorService
    
    [Import(typeof(ITextStructureNavigatorSelectorService))]
    internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
    
  3. Реализуйте метод 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;
    }
    

Реализация действия смарт-тега

К действиям смарт-тегов "

  • Создание 2 с именем класса, сначала UpperCaseSmartTagAction второе и именованное LowerCaseSmartTagAction. Реализация обоих классов ISmartTagAction.

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

Оба класса похожий за исключением того, что один вызывает ToUpper и другие вызовы ToLower. Следующие шаги включают только прописными буквами класс действия, но необходимо реализовать оба класса. Используйте шаги по реализации прописными буквами действие в качестве шаблона для реализации lower-case действие.

  1. Объявите набор закрытых полей.

    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. Добавьте конструктор, который устанавливает поля.

    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. Реализуйте свойства следующим образом.

    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. Реализуйте Invoke метод путем замены текста в диапазоне с прописными буквами числом.

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

Построение и тестирование кода

Для тестирования этого кода выполните построение решения SmartTagTest и запустите его в экспериментальном экземпляре.

Построение и тестирование решение SmartTagTest

  1. Выполните построение решения.

  2. Если запустить этот проект в отладчике, второй экземпляр Visual Studio создается.

  3. Создайте текстовый файл и введите текст.

    Синей линии должна отображаться под первой букве первого машинного слова текста.

  4. Переместите указатель над голубой линией.

    Кнопка должна отображаться рядом указателя.

  5. При нажатии кнопки 2 предложили, что действие должно отображаться: Преобразовать в верхний регистр и Преобразовать в нижний регистр. Если щелкнуть первое действие, то весь текст в текущем машинном слово должно быть преобразовано в верхний регистр. Если выбрана вторая операция, то весь текст должен быть преобразованы в нижний регистр.

См. также

Задачи

Пошаговое руководство: Связывание тип контента в расширение имени файла