演示:创建边距标记

可以使用自定义编辑器扩展自定义编辑器边距的外观。 每当代码注释中出现“todo”一词时,本演示都会将自定义符号放在指示器的边距上。

创建 MEF 项目

  1. 创建 C# VSIX 项目。 (在 “新建项目 ”对话框中,选择 Visual C# /Extensibility,然后选择 VSIX Project。)将解决方案 TodoGlyphTest命名为 。

  2. 添加编辑器分类器项目项。 有关详细信息,请参阅 使用编辑器项模板创建扩展

  3. 删除现有类文件。

定义字形

通过运行 IGlyphFactory 接口来定义字形。

定义字形

  1. 添加类文件并将其命名 TodoGlyphFactory

  2. 使用声明添加以下代码。

    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类。

    internal class TodoGlyphFactory : IGlyphFactory
    
  4. 添加一个专用字段,用于定义字形的尺寸。

    const double m_glyphSize = 16.0;
    
  5. 通过定义字形用户界面 (UI) 元素来实现 GenerateGlyphTodoTag 在本操作说明的后面部分定义。

    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类。 使用NameAttribute“TodoGlyph”、After VsTextMarkerOrderAttributeContentTypeAttribute“code”和 TagTypeAttribute TodoTag 的类导出。

    [Export(typeof(IGlyphFactoryProvider))]
    [Name("TodoGlyph")]
    [Order(After = "VsTextMarker")]
    [ContentType("code")]
    [TagType(typeof(TodoTag))]
    internal sealed class TodoGlyphFactoryProvider : IGlyphFactoryProvider
    
  7. 通过实例化TodoGlyphFactory来实现GetGlyphFactory方法。

    public IGlyphFactory GetGlyphFactory(IWpfTextView view, IWpfTextViewMargin margin)
    {
        return new TodoGlyphFactory();
    }
    

定义 Todo 标记和标记器

定义在前面的步骤中定义的 UI 元素与指示器边距之间的关系。 创建标签类型和标记器,并通过标记器提供程序将其导出。

定义待办事项标记和标记器

  1. 向项目添加新类文件并将其命名 TodoTagger

  2. 添加以下导入。

    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. 的类。

    internal class TodoTag : IGlyphTag
    
  4. 修改名为 TodoTagger 实现 ITagger<T> 类型的 TodoTag类。

    internal class TodoTagger : ITagger<TodoTag>
    
  5. TodoTagger类中,为IClassifier和要在分类范围中查找的文本添加私有字段。

    private IClassifier m_classifier;
    private const string m_searchText = "todo";
    
  6. 添加设置分类器的构造函数。

    internal TodoTagger(IClassifier classifier)
    {
        m_classifier = classifier;
    }
    
  7. 通过查找名称包含“comment”且文本包含搜索文本的所有分类范围来实现GetTags方法。 当找到搜索文本时,生成一个新的TagSpan<T>,类型为TodoTag

    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 EventHandler<SnapshotSpanEventArgs> TagsChanged;
    
  9. 添加一个名为TodoTaggerProvider的类,该类实现ITaggerProvider,并使用ContentTypeAttribute代码和TagTypeAttribute TodoTag导出它。

    [Export(typeof(ITaggerProvider))]
    [ContentType("code")]
    [TagType(typeof(TodoTag))]
    class TodoTaggerProvider : ITaggerProvider
    
  10. 导入IClassifierAggregatorService.

    [Import]
    internal IClassifierAggregatorService AggregatorService;
    
  11. 通过实例化TodoTagger来实现CreateTagger方法。

    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. 带有深蓝色轮廓的浅蓝色圆圈显示在代码窗口左侧的指示器边距中。