演练:创建标志符号边距

使用自定义编辑器扩展,您可以自定义编辑器边距外观。 本演练演示在指示器边距将自定义的标志符号,只要单词 “todo”显示代码注释。

系统必备

若要完成本演练,您必须安装 Visual Studio 2010 SDK。

备注

有关 Visual Studio SDK 的更多信息,请参见 扩展 Visual Studio 概述。若要查找有关中所列如何下载 Visual Studio SDK,请 Visual Studio Extensibility Developer Center 参见 MSDN 网站上。

创建一个 managed extensibility framework 项目 (MEF)

创建 MEF 项目

  1. 创建 Visual c# 或 Visual Basic 编辑器分类器项目。 将解决方案命名为 TodoGlyphTest。

  2. 打开在 VSIX 清单编辑器中的 Source.extension.vsixmanifest 文件。

  3. 确保 Content 归为包含一个 MEF 组件内容类型,而 Path 设置为 TodoGlyphTest.dll。

  4. 保存并关闭的 Source.extension.vsixmanifest。

  5. 删除现有类文件。

定义标志符号

通过实现 IGlyphFactory 接口定义标志符号。

定义标志符号

  1. 将类文件并将其命名为 TodoGlyphFactory。

  2. 添加下面的导入。

    Imports System.ComponentModel.Composition
    Imports System.Windows
    Imports System.Windows.Shapes
    Imports System.Windows.Media
    Imports System.Windows.Controls
    Imports Microsoft.VisualStudio.Text
    Imports Microsoft.VisualStudio.Text.Editor
    Imports Microsoft.VisualStudio.Text.Formatting
    Imports Microsoft.VisualStudio.Text.Tagging
    Imports Microsoft.VisualStudio.Utilities
    
    using System.ComponentModel.Composition;
    using System.Windows;
    using System.Windows.Shapes;
    using System.Windows.Media;
    using System.Windows.Controls;
    using Microsoft.VisualStudio.Text;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Text.Formatting;
    using Microsoft.VisualStudio.Text.Tagging;
    using Microsoft.VisualStudio.Utilities;
    
  3. 添加类被命名为该 TodoGlyphFactory 实现 IGlyphFactory

    Friend Class TodoGlyphFactory
        Implements IGlyphFactory
    
    internal class TodoGlyphFactory : IGlyphFactory
    
  4. 添加定义标志符号的维度的私有字段。

    Const m_glyphSize As Double = 16.0
    
    const double m_glyphSize = 16.0;
    
  5. 通过定义标志符号用户界面元素实现 (UI) GenerateGlyphTodoTag 在本演练的稍后部分中定义。

    Public Function GenerateGlyph(ByVal line As IWpfTextViewLine, ByVal tag As IGlyphTag) As System.Windows.UIElement Implements IGlyphFactory.GenerateGlyph
        ' Ensure we can draw a glyph for this marker. 
        If tag Is Nothing OrElse Not (TypeOf tag Is TodoTag) Then 
            Return Nothing 
        End If 
    
        Dim ellipse As Ellipse = New Ellipse()
        ellipse.Fill = Brushes.LightBlue
        ellipse.StrokeThickness = 2
        ellipse.Stroke = Brushes.DarkBlue
        ellipse.Height = m_glyphSize
        ellipse.Width = m_glyphSize
    
        Return ellipse
    
    End Function
    
    public UIElement GenerateGlyph(IWpfTextViewLine line, IGlyphTag tag)
    {
        // Ensure we can draw a glyph for this marker. 
        if (tag == null || !(tag is TodoTag))
        {
            return null;
        }
    
        System.Windows.Shapes.Ellipse ellipse = new Ellipse();
        ellipse.Fill = Brushes.LightBlue;
        ellipse.StrokeThickness = 2;
        ellipse.Stroke = Brushes.DarkBlue;
        ellipse.Height = m_glyphSize;
        ellipse.Width = m_glyphSize;
    
        return ellipse;
    }
    
  6. 添加类被命名为该 TodoGlyphFactoryProvider 实现 IGlyphFactoryProvider。 导出与 “TodoGlyph” NameAttribute ,在 VsTextMarker 后 OrderAttribute , “代码” ContentTypeAttribute 和 TodoTag TagTypeAttribute 的此类。

    <Export(GetType(IGlyphFactoryProvider)), Name("TodoGlyph"), Order(After:="VsTextMarker"), ContentType("code"), TagType(GetType(TodoTag))>
    Friend NotInheritable Class TodoGlyphFactoryProvider
        Implements IGlyphFactoryProvider
    
    [Export(typeof(IGlyphFactoryProvider))]
    [Name("TodoGlyph")]
    [Order(After = "VsTextMarker")]
    [ContentType("code")]
    [TagType(typeof(TodoTag))]
    internal sealed class TodoGlyphFactoryProvider : IGlyphFactoryProvider
    
  7. 通过实例化 TodoGlyphFactory执行 GetGlyphFactory 方法。

    Public Function GetGlyphFactory(ByVal view As IWpfTextView, ByVal margin As IWpfTextViewMargin) As IGlyphFactory Implements IGlyphFactoryProvider.GetGlyphFactory
        Return New TodoGlyphFactory()
    End Function
    
    public IGlyphFactory GetGlyphFactory(IWpfTextView view, IWpfTextViewMargin margin)
    {
        return new TodoGlyphFactory();
    }
    

定义 Todo 标记和标记

定义在前面的步骤和指示器边距定义通过创建标记类型和标记的 UI 元素和导出它之间的关系通过使用标记提供程序。

定义 todo 标记和标记

  1. 添加新类添加到项目并将其命名为 TodoTagger。

  2. 添加下面的导入。

    Imports System
    Imports System.Collections.Generic
    Imports System.ComponentModel.Composition
    Imports Microsoft.VisualStudio.Text
    Imports Microsoft.VisualStudio.Text.Tagging
    Imports Microsoft.VisualStudio.Text.Editor
    Imports Microsoft.VisualStudio.Text.Classification
    Imports Microsoft.VisualStudio.Utilities
    
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using Microsoft.VisualStudio.Text;
    using Microsoft.VisualStudio.Text.Tagging;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Text.Classification;
    using Microsoft.VisualStudio.Utilities;
    
  3. 将名为 TodoTag的类。

    Friend Class TodoTag
        Implements IGlyphTag
    
        Public Sub New()
            MyBase.New()
        End Sub 
    End Class
    
    internal class TodoTag : IGlyphTag
    
  4. 修改类被命名为该 TodoTagger 类型 TodoTag的实现 ITagger

    Friend Class TodoTagger
        Implements ITagger(Of TodoTag)
    
    internal class TodoTagger : ITagger<TodoTag>
    
  5. TodoTagger 类中,添加私有字段 IClassifier 的且该文本的外观在类范围。

    Private m_classifier As IClassifier
    Private Const m_searchText As String = "todo"
    
    private IClassifier m_classifier;
    private const string m_searchText = "todo";
    
  6. 添加一组分类器的构造函数。

    Friend Sub New(ByVal classifier As IClassifier)
        m_classifier = classifier
    End Sub
    
    internal TodoTagger(IClassifier classifier)
    {
        m_classifier = classifier;
    }
    
  7. 通过查找名称中包含单词 “注释”,并包含的文本搜索文本的所有类范围执行 GetTags 方法。 只要找到搜索文本,请在给定类型 TodoTagTagSpan

    Private Function GetTags(ByVal spans As NormalizedSnapshotSpanCollection) As IEnumerable(Of ITagSpan(Of TodoTag)) Implements ITagger(Of TodoTag).GetTags
        Dim list As List(Of ITagSpan(Of TodoTag))
        list = New List(Of ITagSpan(Of TodoTag))()
    
        For Each span As SnapshotSpan In spans
            'look at each classification span \ 
            For Each classification As ClassificationSpan In m_classifier.GetClassificationSpans(span)
                'if the classification is a comment 
                If classification.ClassificationType.Classification.ToLower().Contains("comment") Then 
                    'if the word "todo" is in the comment, 
                    'create a new TodoTag TagSpan 
                    Dim index As Integer = classification.Span.GetText().ToLower().IndexOf(m_searchText)
                    If index <> -1 Then
                        list.Add(New TagSpan(Of TodoTag)(New SnapshotSpan(classification.Span.Start + index, m_searchText.Length), New TodoTag()))
                    End If 
                End If 
            Next classification
        Next span
    
        Return list
    End Function
    
    IEnumerable<ITagSpan<TodoTag>> ITagger<TodoTag>.GetTags(NormalizedSnapshotSpanCollection spans)
    {
        foreach (SnapshotSpan span in spans)
        {
            //look at each classification span \ 
            foreach (ClassificationSpan classification in m_classifier.GetClassificationSpans(span))
            {
                //if the classification is a comment 
                if (classification.ClassificationType.Classification.ToLower().Contains("comment"))
                {
                    //if the word "todo" is in the comment,
                    //create a new TodoTag TagSpan 
                    int index = classification.Span.GetText().ToLower().IndexOf(m_searchText);
                    if (index != -1)
                    {
                        yield return new TagSpan<TodoTag>(new SnapshotSpan(classification.Span.Start + index, m_searchText.Length), new TodoTag());
                    }
                }
            }
        }
    }
    
  8. 声明 TagsChanged 事件。

    Public Event TagsChanged(ByVal sender As Object, ByVal e As Microsoft.VisualStudio.Text.SnapshotSpanEventArgs) Implements Microsoft.VisualStudio.Text.Tagging.ITagger(Of TodoTag).TagsChanged
    
    public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
    
  9. 添加实现 ITaggerProvider名为 TodoTaggerProvider 的类,并将其导出与 “代码” ContentTypeAttribute 和 TodoTag TagTypeAttribute

    <Export(GetType(ITaggerProvider)), ContentType("code"), TagType(GetType(TodoTag))>
    Friend Class TodoTaggerProvider
        Implements ITaggerProvider
    
    [Export(typeof(ITaggerProvider))]
    [ContentType("code")]
    [TagType(typeof(TodoTag))]
    class TodoTaggerProvider : ITaggerProvider
    
  10. 导入 IClassifierAggregatorService

    <Import()>
    Friend AggregatorService As IClassifierAggregatorService
    
    [Import]
    internal IClassifierAggregatorService AggregatorService;
    
  11. 通过实例化 TodoTagger执行 CreateTagger``1 方法。

    Public Function CreateTagger(Of T As Microsoft.VisualStudio.Text.Tagging.ITag)(ByVal buffer As Microsoft.VisualStudio.Text.ITextBuffer) As Microsoft.VisualStudio.Text.Tagging.ITagger(Of T) Implements Microsoft.VisualStudio.Text.Tagging.ITaggerProvider.CreateTagger
        If buffer Is Nothing Then 
            Throw New ArgumentNullException("buffer")
        End If 
    
        Return TryCast(New TodoTagger(AggregatorService.GetClassifier(buffer)), ITagger(Of T))
    End Function
    
    public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
    {
        if (buffer == null)
        {
            throw new ArgumentNullException("buffer");
        }
    
        return new TodoTagger(AggregatorService.GetClassifier(buffer)) as ITagger<T>;
    }
    

生成并测试代码

若要测试此代码,请生成 TodoGlyphTest 解决方案并运行在的实验实例。

生成和测试 TodoGlyphTest 解决方案

  1. 生成解决方案。

  2. 通过按 F5 键运行项目。 Visual Studio 的第二个实例进行实例化。

  3. 确保指示器边距显示。 (在 工具 菜单上,单击 选项。 在 文本编辑器 页上,确保 指示器边距 已选中。)

  4. 打开包含注释的代码文件。 添加单词 “todo”某个批注部分。

  5. 有一个后者一个轮廓浅蓝色的圆形应出现在指示器边距在代码窗口左侧。