다음을 통해 공유


연습: 여백 문자 모양 만들기

사용자 지정 편집기 확장을 사용하여 편집기 여백의 모양을 사용자 지정할 수 있습니다. 이 연습에서는 코드 주석에 “todo”라는 단어가 나타날 때마다 표시기 여백에 사용자 지정 문자 모양을 배치합니다.

MEF 프로젝트 만들기

  1. C# VSIX 프로젝트를 만듭니다. (새 프로젝트 대화 상자에서 Visual C#/확장성, VSIX 프로젝트를 차례로 선택합니다.) 솔루션 이름을 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. IGlyphFactory를 구현하는 TodoGlyphFactory라는 클래스를 추가합니다.

    internal class TodoGlyphFactory : IGlyphFactory
    
  4. 문자 모양의 차원을 정의하는 프라이빗 필드를 추가합니다.

    const double m_glyphSize = 16.0;
    
  5. 문자 모양 UI(사용자 인터페이스) 요소를 정의하여 GenerateGlyph를 구현합니다. TodoTag는 이 연습의 뒷부분에서 정의됩니다.

    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. IGlyphFactoryProvider를 구현하는 TodoGlyphFactoryProvider라는 클래스를 추가합니다. “TodoGlyph”의 NameAttribute, After VsTextMarker의 OrderAttribute, “code”의 ContentTypeAttribute, TodoTag의 TagTypeAttribute를 사용하여 이 클래스를 내보냅니다.

    [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 요소와 표시기 여백 간 관계를 정의합니다. 태그 형식 및 태거를 만들고 태거 공급자를 사용하여 내보냅니다.

Todo 태그 및 태거를 정의하려면

  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. TodoTag 형식의 ITagger<T>를 구현하는 TodoTagger라는 클래스를 수정합니다.

    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 메서드를 구현합니다. 검색 텍스트를 찾을 때마다 TodoTag 형식의 새로운 TagSpan<T>를 일시 중단합니다.

    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. ITaggerProvider를 구현하는 TodoTaggerProvider라는 클래스를 만들고, “code”의 ContentTypeAttribute 및 TodoTag의 TagTypeAttribute를 사용하여 내보냅니다.

    [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. 코드 창 왼쪽의 표시기 여백에 진한 파란색 윤곽선이 있는 연한 파란색 원이 나타납니다.