다음을 통해 공유


연습: 확장 편집기를 셸 명령 사용

있는 Vspackage를 편집기로 메뉴 명령과 같은 기능을 추가할 수 있습니다. 이 연습에서는 메뉴 명령을 호출 하 여 텍스트 뷰 편집기에서에 장식 추가 하는 방법을 보여 줍니다.

이 연습에서는 있는 VSPackage 확장성 프레임 워크 (MEF) 관리 되는 구성 요소 부품과 함께 사용 하는 방법을 보여 줍니다. Visual Studio 셸을 사용 하 여 메뉴 명령을 등록할 수 있는 Vspackage를 사용 해야 하며 MEF 컴포넌트 부품에 액세스 하려면 명령을 사용할 수 있습니다.

사전 요구 사항

이 연습을 완료 하려면 설치 해야 해당 Visual Studio 2010 SDK.

참고

Visual Studio SDK에 대 한 자세한 내용은 참조 하십시오. Visual Studio 개요를 확장합니다..Visual Studio SDK를 다운로드 하는 방법를 참조 하십시오. Visual Studio 확장성 개발자 센터 MSDN 웹 사이트에서.

Visual Studio 패키지 프로젝트 템플릿에 대해 위치

세 가지 다른 위치에서 찾을 수 있습니다 Visual Studio 패키지 프로젝트 서식 파일은 새 프로젝트 대화 상자:

  1. 아래에서 Visual Basic 확장성. 프로젝트의 기본 언어는 Visual Basic입니다.

  2. C#에서 확장 합니다. 프로젝트의 기본 언어는 C#입니다.

  3. 아래에서 기타 프로젝트 형식 확장성. C + + 프로젝트의 기본 언어가입니다.

메뉴 명령을 VSPackage 만들기

라는 메뉴 명령 배치는 VSPackage 만들기 장식 추가 에 있는 도구 메뉴.

메뉴 명령을 Vspackage를 만들려면

  1. Visual Studio 패키지를 만들고 이름을 MenuCommandTest. 확인을 클릭합니다.

  2. 시작 페이지에서 클릭 다음.

  3. 에 있는 프로그래밍 언어 선택 페이지에서 선택 Visual Basic 또는 **C#**을 새 어셈블리에 서명 하려면 키 파일을 생성 을 선택 하 고 다음을 클릭 다음.

  4. 기본 VSPackage 정보 페이지에 있는 VSPackage 이름 형식 상자 메뉴 명령, 클릭 하 고 다음을 클릭 다음.

  5. 에 있는 VSPackage 옵션 선택 페이지에서 선택 메뉴 명령 을 하 고 다음을 클릭 다음.

  6. 명령 옵션 페이지에 있는 명령 이름 형식 상자 장식 추가. 에 있는 명령 ID 상자에 입력 cmdidAddAdornment. 다음을 클릭합니다.

  7. 에 있는 테스트 옵션 선택 페이지에서 두 옵션의 선택을 취소 하 고 다음을 클릭 완료.

  8. MenuCommandTest 이라는 솔루션을 열었습니다. 메뉴 명령을 생성 하 고 배치 코드는 MenuCommandTestPackage 파일에 있는 해당 도구 메뉴입니다. 이 명령은 메시지 상자를 표시 하는 바로 됩니다. 이후 단계를 주석 장식 표시 하려면이 변경 하는 방법을 보여 줍니다.

  9. VSIX 매니페스트 편집기에서 source.extension.vsixmanifest 파일을 엽니다. 하나 있어야 Content 있는 VSPackage 메뉴 명령 이름이 지정 된 행입니다.

  10. 저장 한 Source.extension.vsixmanifest 파일을 닫습니다.

MEF 확장 VSPackage 솔루션에 추가

MEF 확장 VSPackage 솔루션에 추가 하려면

  1. 솔루션 탐색기에서 솔루션 노드를 마우스 오른쪽 단추로 클릭한 다음 추가, 새 프로젝트를 차례로 클릭합니다. 에 있는 새 프로젝트 추가 대화 상자에서 클릭에서 확장성 Visual Basic 또는 C#, 다음 EditorClassifier. 프로젝트의 이름을 CommentAdornmentTest.

  2. 이 프로젝트 VSPackage 강력한 이름의 어셈블리와 상호 작용 하는 때문에 어셈블리를 서명 해야 합니다. 키 파일이 이미 VSPackage 어셈블리를 만들어 다시 사용할 수 있습니다.

    1. 프로젝트 속성을 열고 선택은 서명 페이지입니다.

    2. 선택 어셈블리 서명.

    3. 아래에서 강력한 이름 키 파일 선택, MenuCommandTest 어셈블리에 대해 생성 된 Key.snk 파일을 선택 합니다.

    4. 프로젝트를 저장합니다.

MEF 확장 VSPackage 프로젝트 참조

MEF 컴포넌트 Vspackage를 추가 하는 때문에 두 종류의 내용 매니페스트를 지정 해야 합니다.

참고

MEF에 대한 자세한 내용은 MEF(Managed Extensibility Framework)를 참조하십시오.

MEF VSPackage 프로젝트 구성 요소를 참조 하려면

  1. MenuCommandTest 프로젝트에서 VSIX Manifest 편집기에서 source.extension.vsixmanifest 파일을 엽니다.

  2. 아래는 콘텐츠 제목를 클릭 추가 콘텐츠. 에 있는 콘텐츠 형식 선택 목록에서 MEF 구성 요소. 아래에서 소스 선택, CommentAdornmentTest.

  3. 저장 한 source.extension.vsixmanifest 파일을 닫습니다.

  4. CommentAdornmentTest 프로젝트에 참조를 추가 합니다.

주석 장식 정의

주석 장식으로 구성 되어 있는 ITrackingSpan 선택한 텍스트 및 작성자 및 텍스트에 대 한 일부 문자열 추적 합니다.

주석 장식 정의 하기

  1. CommentAdornmentTest 프로젝트에 기존 클래스 파일을 삭제 합니다.

  2. 새 클래스 파일을 추가 하 고 이름을 CommentAdornment.

  3. 다음 추가 using 문의입니다.

    Imports Microsoft.VisualStudio.Text
    
    using Microsoft.VisualStudio.Text;
    
  4. 라는 클래스를 추가 합니다. CommentAdornment.

    Friend Class CommentAdornment
    
    internal class CommentAdornment
    
  5. 세 개의 필드를 추가 CommentAdornment 에 대 한 클래스는 ITrackingSpan, 만든이 및 설명.

    Public ReadOnly Span As ITrackingSpan
    Public ReadOnly Author As String 
    Public ReadOnly Text As String
    
    public readonly ITrackingSpan Span;
    public readonly string Author;
    public readonly string Text;
    
  6. 필드를 초기화 하는 생성자를 추가 합니다.

    Public Sub New(ByVal span As SnapshotSpan, ByVal author As String, ByVal text As String)
        Me.Span = span.Snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeExclusive)
        Me.Author = author
        Me.Text = text
    End Sub
    
    public CommentAdornment(SnapshotSpan span, string author, string text)
    {
        this.Span = span.Snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeExclusive);
        this.Author = author;
        this.Text = text;
    }
    

장식의 시각적 요소를 만들기

또한 사용자에 대 한 장식 시각적 요소를 정의 해야 합니다. 이 연습에서는 Windows Presentation Foundation (WPF) 클래스에서 상속 되는 컨트롤 정의 Canvas.

있는 장식의 시각적 요소를 만들려면

  1. CommentAdornmentTest 프로젝트의 클래스를 만들고 이름을 CommentBlock.

  2. 다음 추가 using 문입니다.

    Imports System
    Imports System.Windows
    Imports System.Windows.Controls
    Imports System.Windows.Media
    Imports System.Windows.Shapes
    
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Shapes;
    
  3. 하는 CommentBlock 클래스에서 상속 Canvas.

    Friend Class CommentBlock
        Inherits Canvas
    
    internal class CommentBlock : Canvas
    
  4. 있는 장식의 시각적 측면을 정의 합니다 일부 private 필드를 추가 합니다.

    Private textGeometry As Geometry
    Private commentGrid As Grid
    Private Shared brush As Brush
    Private Shared solidPen As Pen
    Private Shared dashPen As Pen
    
    private Geometry textGeometry;
    private Grid commentGrid;
    private static Brush brush;
    private static Pen solidPen;
    private static Pen dashPen;
    
  5. 주석 장식 정의 하 고 해당 텍스트를 추가 하는 생성자를 추가 합니다.

    Public Sub New(ByVal textRightEdge As Double, ByVal viewRightEdge As Double, ByVal newTextGeometry As Geometry, ByVal author As String, ByVal body As String)
        If brush Is Nothing Then
            brush = New SolidColorBrush(Color.FromArgb(&H20, &H0, &HFF, &H0))
            brush.Freeze()
            Dim penBrush As Brush = New SolidColorBrush(Colors.Green)
            penBrush.Freeze()
            solidPen = New Pen(penBrush, 0.5)
            solidPen.Freeze()
            dashPen = New Pen(penBrush, 0.5)
            dashPen.DashStyle = DashStyles.Dash
            dashPen.Freeze()
        End If 
    
        Me.textGeometry = newTextGeometry
    
        Dim tb1 As New TextBlock()
        tb1.Text = author
        Dim tb2 As New TextBlock()
        tb2.Text = body
    
        Const MarginWidth As Integer = 8
        Me.commentGrid = New Grid()
        Me.commentGrid.RowDefinitions.Add(New RowDefinition())
        Me.commentGrid.RowDefinitions.Add(New RowDefinition())
        Dim cEdge As New ColumnDefinition()
        cEdge.Width = New GridLength(MarginWidth)
        Dim cEdge2 As New ColumnDefinition()
        cEdge2.Width = New GridLength(MarginWidth)
        Me.commentGrid.ColumnDefinitions.Add(cEdge)
        Me.commentGrid.ColumnDefinitions.Add(New ColumnDefinition())
        Me.commentGrid.ColumnDefinitions.Add(cEdge2)
    
        Dim rect As New System.Windows.Shapes.Rectangle()
        rect.RadiusX = 6
        rect.RadiusY = 3
        rect.Fill = brush
        rect.Stroke = Brushes.Green
    
        Dim inf As New Size(Double.PositiveInfinity, Double.PositiveInfinity)
        tb1.Measure(inf)
        tb2.Measure(inf)
        Dim middleWidth As Double = Math.Max(tb1.DesiredSize.Width, tb2.DesiredSize.Width)
        Me.commentGrid.Width = middleWidth + 2 * MarginWidth
        Grid.SetColumn(rect, 0)
        Grid.SetRow(rect, 0)
        Grid.SetRowSpan(rect, 2)
        Grid.SetColumnSpan(rect, 3)
        Grid.SetRow(tb1, 0)
        Grid.SetColumn(tb1, 1)
        Grid.SetRow(tb2, 1)
        Grid.SetColumn(tb2, 1)
        Me.commentGrid.Children.Add(rect)
        Me.commentGrid.Children.Add(tb1)
        Me.commentGrid.Children.Add(tb2)
    
        Canvas.SetLeft(Me.commentGrid, Math.Max(viewRightEdge - Me.commentGrid.Width - 20.0, textRightEdge + 20.0))
        Canvas.SetTop(Me.commentGrid, textGeometry.GetRenderBounds(solidPen).Top)
    
        Me.Children.Add(Me.commentGrid)
    End Sub
    
    public CommentBlock(double textRightEdge,
    double viewRightEdge,
    Geometry newTextGeometry,
    string author,
    string body)
    {
        if (brush == null)
        {
            brush = new SolidColorBrush(Color.FromArgb(0x20, 0x00, 0xff, 0x00));
            brush.Freeze();
            Brush penBrush = new SolidColorBrush(Colors.Green);
            penBrush.Freeze();
            solidPen = new Pen(penBrush, 0.5);
            solidPen.Freeze();
            dashPen = new Pen(penBrush, 0.5);
            dashPen.DashStyle = DashStyles.Dash;
            dashPen.Freeze();
        }
    
        this.textGeometry = newTextGeometry;
    
        TextBlock tb1 = new TextBlock();
        tb1.Text = author;
        TextBlock tb2 = new TextBlock();
        tb2.Text = body;
    
        const int MarginWidth = 8;
        this.commentGrid = new Grid();
        this.commentGrid.RowDefinitions.Add(new RowDefinition());
        this.commentGrid.RowDefinitions.Add(new RowDefinition());
        ColumnDefinition cEdge = new ColumnDefinition();
        cEdge.Width = new GridLength(MarginWidth);
        ColumnDefinition cEdge2 = new ColumnDefinition();
        cEdge2.Width = new GridLength(MarginWidth);
        this.commentGrid.ColumnDefinitions.Add(cEdge);
        this.commentGrid.ColumnDefinitions.Add(new ColumnDefinition());
        this.commentGrid.ColumnDefinitions.Add(cEdge2);
    
        System.Windows.Shapes.Rectangle rect = new System.Windows.Shapes.Rectangle();
        rect.RadiusX = 6;
        rect.RadiusY = 3;
        rect.Fill = brush;
        rect.Stroke = Brushes.Green;
    
        Size inf = new Size(double.PositiveInfinity, double.PositiveInfinity);
        tb1.Measure(inf);
        tb2.Measure(inf);
        double middleWidth = Math.Max(tb1.DesiredSize.Width, tb2.DesiredSize.Width);
        this.commentGrid.Width = middleWidth + 2 * MarginWidth;
    
        Grid.SetColumn(rect, 0);
        Grid.SetRow(rect, 0);
        Grid.SetRowSpan(rect, 2);
        Grid.SetColumnSpan(rect, 3);
        Grid.SetRow(tb1, 0);
        Grid.SetColumn(tb1, 1);
        Grid.SetRow(tb2, 1);
        Grid.SetColumn(tb2, 1);
        this.commentGrid.Children.Add(rect);
        this.commentGrid.Children.Add(tb1);
        this.commentGrid.Children.Add(tb2);
    
        Canvas.SetLeft(this.commentGrid, Math.Max(viewRightEdge - this.commentGrid.Width - 20.0, textRightEdge + 20.0));
        Canvas.SetTop(this.commentGrid, textGeometry.GetRenderBounds(solidPen).Top);
    
        this.Children.Add(this.commentGrid);
    }
    
  6. 수도 OnRender 그립니다를 장식 하는 이벤트 처리기입니다.

    Protected Overrides Sub OnRender(ByVal dc As DrawingContext)
        MyBase.OnRender(dc)
        If Me.textGeometry IsNot Nothing Then
            dc.DrawGeometry(brush, solidPen, Me.textGeometry)
            Dim textBounds As Rect = Me.textGeometry.GetRenderBounds(solidPen)
            Dim p1 As New Point(textBounds.Right, textBounds.Bottom)
            Dim p2 As New Point(Math.Max(Canvas.GetLeft(Me.commentGrid) - 20.0, p1.X), p1.Y)
            Dim p3 As New Point(Math.Max(Canvas.GetLeft(Me.commentGrid), p1.X), (Canvas.GetTop(Me.commentGrid) + p1.Y) * 0.5)
            dc.DrawLine(dashPen, p1, p2)
            dc.DrawLine(dashPen, p2, p3)
        End If 
    End Sub
    
    protected override void OnRender(DrawingContext dc)
    {
        base.OnRender(dc);
        if (this.textGeometry != null)
        {
            dc.DrawGeometry(brush, solidPen, this.textGeometry);
            Rect textBounds = this.textGeometry.GetRenderBounds(solidPen);
            Point p1 = new Point(textBounds.Right, textBounds.Bottom);
            Point p2 = new Point(Math.Max(Canvas.GetLeft(this.commentGrid) - 20.0, p1.X), p1.Y);
            Point p3 = new Point(Math.Max(Canvas.GetLeft(this.commentGrid), p1.X), (Canvas.GetTop(this.commentGrid) + p1.Y) * 0.5);
            dc.DrawLine(dashPen, p1, p2);
            dc.DrawLine(dashPen, p2, p3);
        }
    }
    

추가 하는 IWpfTextViewCreationListener

IWpfTextViewCreationListener 들을 만드는 이벤트를 볼 수 있습니다 MEF 구성 요소의 일부입니다.

Iwpftextviewcreationlistener을 추가 하려면

  1. CommentAdornmentTest 프로젝트에 클래스 파일을 추가 하 고 이름을 커넥터.

  2. 다음 추가 using 문입니다.

    Imports System.ComponentModel.Composition
    Imports Microsoft.VisualStudio.Text.Editor
    Imports Microsoft.VisualStudio.Utilities
    
    using System.ComponentModel.Composition;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Utilities;
    
  3. 구현 하는 클래스를 선언 합니다. IWpfTextViewCreationListener 함께 내보낼는 ContentTypeAttribute "텍스트"와 a TextViewRoleAttributeDocument. 콘텐츠 형식 특성 종류의 콘텐츠를 적용 되는 구성 요소를 지정 합니다. 텍스트 형식의 모든 이진 파일 형식에 대 한 기본 형식이입니다. 따라서 이러한 종류의 만든 거의 모든 텍스트 보기가 됩니다. 텍스트 보기 역할 특성 적용 되는 구성 요소 텍스트 보기의 종류를 지정 합니다. 일반적으로 문서의 텍스트 보기 역할 줄의 구성 되며 파일에 저장 되는 텍스트를 표시 합니다.

    <Export(GetType(IWpfTextViewCreationListener)), ContentType("text"), TextViewRole(PredefinedTextViewRoles.Document)>
    Public NotInheritable Class Connector
        Implements IWpfTextViewCreationListener
    
    [Export(typeof(IWpfTextViewCreationListener))]
    [ContentType("text")]
    [TextViewRole(PredefinedTextViewRoles.Document)]
    public sealed class Connector : IWpfTextViewCreationListener
    
  4. 구현은 TextViewCreated 하 여 정적 호출 하도록 메서드 Create() 의 이벤트는 CommentAdornmentManager.

    Public Sub TextViewCreated(ByVal textView As IWpfTextView) Implements IWpfTextViewCreationListener.TextViewCreated
        CommentAdornmentManager.Create(textView)
    End Sub
    
    public void TextViewCreated(IWpfTextView textView)
    {
        CommentAdornmentManager.Create(textView);
    }
    
  5. 명령을 실행 하는 데 사용할 수 있는 메서드를 추가 합니다.

    Public Shared Sub Execute(ByVal host As IWpfTextViewHost)
        Dim view As IWpfTextView = host.TextView
        'Add a comment on the selected text. 
        If Not view.Selection.IsEmpty Then 
            'Get the provider for the comment adornments in the property bag of the view. 
            Dim provider As CommentAdornmentProvider = view.Properties.GetProperty(Of CommentAdornmentProvider)(GetType(CommentAdornmentProvider))
    
            'Add some arbitrary author and comment text. 
            Dim author As String = System.Security.Principal.WindowsIdentity.GetCurrent().Name
            Dim comment As String = "Four score...." 
    
            'Add the comment adornment using the provider.
            provider.Add(view.Selection.SelectedSpans(0), author, comment)
        End If 
    End Sub
    
    static public void Execute(IWpfTextViewHost host)
    {
        IWpfTextView view = host.TextView;
        //Add a comment on the selected text. 
        if (!view.Selection.IsEmpty)
        {
            //Get the provider for the comment adornments in the property bag of the view.
            CommentAdornmentProvider provider = view.Properties.GetProperty<CommentAdornmentProvider>(typeof(CommentAdornmentProvider));
    
            //Add some arbitrary author and comment text. 
            string author = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
            string comment = "Four score....";
    
            //Add the comment adornment using the provider.
            provider.Add(view.Selection.SelectedSpans[0], author, comment);
        }
    }
    

장식 하는 계층을 정의합니다.

새로운 장식 추가 장식 레이어를 정의 해야 합니다.

장식 레이어를 정의 하려면

  • Connector 클래스 형식의 공용 필드를 선언 AdornmentLayerDefinition 함께 내보낼는 NameAttribute 장식 계층에 고유한 이름을 지정 하는 OrderAttribute 다른 텍스트 뷰 레이어를 (텍스트, 캐럿, 및 선택)이 장식 계층의 Z 순서 관계 정의.

    <Export(GetType(AdornmentLayerDefinition)), Name("CommentAdornmentLayer"), Order(After:=PredefinedAdornmentLayers.Selection, Before:=PredefinedAdornmentLayers.Text)>
    Public commentLayerDefinition As AdornmentLayerDefinition
    
    [Export(typeof(AdornmentLayerDefinition))]
    [Name("CommentAdornmentLayer")]
    [Order(After = PredefinedAdornmentLayers.Selection, Before = PredefinedAdornmentLayers.Text)]
    public AdornmentLayerDefinition commentLayerDefinition;
    

주석 장식 제공

도 장식 정의할 때 주석 장식 공급자 및 주석 장식 관리자를 구현 합니다. 주석 장식 공급자 주석 장식 목록을 보관, 수신 Changed 이벤트에서 기본 텍스트 버퍼 및 기본 텍스트를 삭제 하면 삭제 주석 장식 합니다.

주석 장식 공급자를 추가 하려면

  1. CommentAdornmentTest 프로젝트에 새 클래스 파일을 추가 하 고 이름을 CommentAdornmentProvider.

  2. 다음 추가 using 문입니다.

    Imports System
    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    Imports Microsoft.VisualStudio.Text
    Imports Microsoft.VisualStudio.Text.Editor
    
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using Microsoft.VisualStudio.Text;
    using Microsoft.VisualStudio.Text.Editor;
    
  3. 라는 클래스를 추가 합니다. CommentAdornmentProvider.

    Friend Class CommentAdornmentProvider
    
    internal class CommentAdornmentProvider
    
  4. 텍스트 버퍼 및 버퍼에 관련 된 주석 장식의 목록에 대 한 private 필드를 추가 합니다.

    Private buffer As ITextBuffer
    Private comments As IList(Of CommentAdornment) = New List(Of CommentAdornment)()
    
    private ITextBuffer buffer;
    private IList<CommentAdornment> comments = new List<CommentAdornment>();
    
  5. 생성자에 대 한 추가 CommentAdornmentProvider. 공급자가 인스턴스화될 수 있기 때문에 개인 액세스가이 생성자가 있어야 해당 Create() 메서드. 추가 생성자는 OnBufferChanged 이벤트 처리기에는 Changed 이벤트.

    Private Sub New(ByVal buffer As ITextBuffer)
        Me.buffer = buffer
        'listen to the Changed event so we can react to deletions. 
        AddHandler Me.buffer.Changed, AddressOf OnBufferChanged
    End Sub
    
    private CommentAdornmentProvider(ITextBuffer buffer)
    {
        this.buffer = buffer;
        //listen to the Changed event so we can react to deletions. 
        this.buffer.Changed += OnBufferChanged;
    }
    
  6. 추가 Create() 메서드가 있습니다.

    Public Shared Function Create(ByVal view As IWpfTextView) As CommentAdornmentProvider
        Return view.Properties.GetOrCreateSingletonProperty(Of CommentAdornmentProvider)(Function() New CommentAdornmentProvider(view.TextBuffer))
    End Function
    
    public static CommentAdornmentProvider Create(IWpfTextView view)
    {
        return view.Properties.GetOrCreateSingletonProperty<CommentAdornmentProvider>(delegate { return new CommentAdornmentProvider(view.TextBuffer); });
    }
    
  7. 추가 Detach() 메서드가 있습니다.

    Public Sub Detach()
        If Me.buffer IsNot Nothing Then 
            'remove the Changed listener 
            RemoveHandler Me.buffer.Changed, AddressOf OnBufferChanged
            Me.buffer = Nothing 
        End If 
    End Sub
    
    public void Detach()
    {
        if (this.buffer != null)
        {
            //remove the Changed listener 
            this.buffer.Changed -= OnBufferChanged;
            this.buffer = null;
        }
    }
    
  8. 추가 OnBufferChanged 이벤트 처리기입니다.

    Private Sub OnBufferChanged(ByVal sender As Object, ByVal e As TextContentChangedEventArgs)
        'Make a list of all comments that have a span of at least one character after applying the change. There is no need to raise a changed event for the deleted adornments. The adornments are deleted only if a text change would cause the view to reformat the line and discard the adornments. 
        Dim keptComments As IList(Of CommentAdornment) = New List(Of CommentAdornment)(Me.comments.Count)
    
        For Each comment As CommentAdornment In Me.comments
            Dim span As Span = comment.Span.GetSpan(e.After)
            'if a comment does not span at least one character, its text was deleted. 
            If span.Length <> 0 Then
                keptComments.Add(comment)
            End If 
        Next comment
    
        Me.comments = keptComments
    End Sub
    
    private void OnBufferChanged(object sender, TextContentChangedEventArgs e)
    {
        //Make a list of all comments that have a span of at least one character after applying the change. There is no need to raise a changed event for the deleted adornments. The adornments are deleted only if a text change would cause the view to reformat the line and discard the adornments.
        IList<CommentAdornment> keptComments = new List<CommentAdornment>(this.comments.Count);
    
        foreach (CommentAdornment comment in this.comments)
        {
            Span span = comment.Span.GetSpan(e.After);
            //if a comment does not span at least one character, its text was deleted. 
            if (span.Length != 0)
            {
                keptComments.Add(comment);
            }
        }
    
        this.comments = keptComments;
    }
    
  9. 추가 선언에는 CommentsChanged 이벤트.

    Public Event CommentsChanged As EventHandler(Of CommentsChangedEventArgs)
    
    public event EventHandler<CommentsChangedEventArgs> CommentsChanged;
    
  10. 생성 된 Add() 메서드를 장식 합니다.

    Public Sub Add(ByVal span As SnapshotSpan, ByVal author As String, ByVal text As String)
        If span.Length = 0 Then 
            Throw New ArgumentOutOfRangeException("span")
        End If 
        If author Is Nothing Then 
            Throw New ArgumentNullException("author")
        End If 
        If text Is Nothing Then 
            Throw New ArgumentNullException("text")
        End If 
    
        'Create a comment adornment given the span, author and text. 
        Dim comment As New CommentAdornment(span, author, text)
    
        'Add it to the list of comments. 
        Me.comments.Add(comment)
    
        'Raise the changed event. 
        Dim commentsChanged As EventHandler(Of CommentsChangedEventArgs) = Me.CommentsChangedEvent
        If CommentsChangedEvent IsNot Nothing Then
            CommentsChangedEvent(Me, New CommentsChangedEventArgs(comment, Nothing))
        End If 
    End Sub
    
    public void Add(SnapshotSpan span, string author, string text)
    {
        if (span.Length == 0)
            throw new ArgumentOutOfRangeException("span");
        if (author == null)
            throw new ArgumentNullException("author");
        if (text == null)
            throw new ArgumentNullException("text");
    
        //Create a comment adornment given the span, author and text.
        CommentAdornment comment = new CommentAdornment(span, author, text);
    
        //Add it to the list of comments. 
        this.comments.Add(comment);
    
        //Raise the changed event.
        EventHandler<CommentsChangedEventArgs> commentsChanged = this.CommentsChanged;
        if (commentsChanged != null)
            commentsChanged(this, new CommentsChangedEventArgs(comment, null));
    }
    
  11. RemoveComments() 메서드를 추가합니다.

    Public Sub RemoveComments(ByVal span As SnapshotSpan)
        Dim commentsChanged As EventHandler(Of CommentsChangedEventArgs) = Me.CommentsChangedEvent
    
        'Get a list of all the comments that are being kept  
        Dim keptComments As IList(Of CommentAdornment) = New List(Of CommentAdornment)(Me.comments.Count)
    
        For Each comment As CommentAdornment In Me.comments
            'find out if the given span overlaps with the comment text span. If two spans are adjacent, they do not overlap. To consider adjacent spans, use IntersectsWith. 
            If comment.Span.GetSpan(span.Snapshot).OverlapsWith(span) Then 
                'Raise the change event to delete this comment. 
                If CommentsChangedEvent IsNot Nothing Then
                    CommentsChangedEvent(Me, New CommentsChangedEventArgs(Nothing, comment))
                End If 
            Else
                keptComments.Add(comment)
            End If 
        Next comment
    
        Me.comments = keptComments
    End Sub
    
    public void RemoveComments(SnapshotSpan span)
    {
        EventHandler<CommentsChangedEventArgs> commentsChanged = this.CommentsChanged;
    
        //Get a list of all the comments that are being kept 
        IList<CommentAdornment> keptComments = new List<CommentAdornment>(this.comments.Count);
    
        foreach (CommentAdornment comment in this.comments)
        {
            //find out if the given span overlaps with the comment text span. If two spans are adjacent, they do not overlap. To consider adjacent spans, use IntersectsWith. 
            if (comment.Span.GetSpan(span.Snapshot).OverlapsWith(span))
            {
                //Raise the change event to delete this comment. 
                if (commentsChanged != null)
                    commentsChanged(this, new CommentsChangedEventArgs(null, comment));
            }
            else
                keptComments.Add(comment);
        }
    
        this.comments = keptComments;
    }
    
  12. 추가 된 GetComments() 스냅샷을 지정 된 범위에 있는 메모를 모두 반환 하는 메서드.

    Public Function GetComments(ByVal span As SnapshotSpan) As Collection(Of CommentAdornment)
        Dim overlappingComments As IList(Of CommentAdornment) = New List(Of CommentAdornment)()
        For Each comment As CommentAdornment In Me.comments
            If comment.Span.GetSpan(span.Snapshot).OverlapsWith(span) Then
                overlappingComments.Add(comment)
            End If 
        Next comment
    
        Return New Collection(Of CommentAdornment)(overlappingComments)
    End Function
    
    public Collection<CommentAdornment> GetComments(SnapshotSpan span)
    {
        IList<CommentAdornment> overlappingComments = new List<CommentAdornment>();
        foreach (CommentAdornment comment in this.comments)
        {
            if (comment.Span.GetSpan(span.Snapshot).OverlapsWith(span))
                overlappingComments.Add(comment);
        }
    
        return new Collection<CommentAdornment>(overlappingComments);
    }
    
  13. 라는 클래스를 추가 합니다. CommentsChangedEventArgs, 다음과 같이 합니다.

    Friend Class CommentsChangedEventArgs
        Inherits EventArgs
        Public ReadOnly CommentAdded As CommentAdornment
        Public ReadOnly CommentRemoved As CommentAdornment
    
        Public Sub New(ByVal added As CommentAdornment, ByVal removed As CommentAdornment)
            Me.CommentAdded = added
            Me.CommentRemoved = removed
        End Sub 
    End Class
    
    internal class CommentsChangedEventArgs : EventArgs
    {
        public readonly CommentAdornment CommentAdded;
    
        public readonly CommentAdornment CommentRemoved;
    
        public CommentsChangedEventArgs(CommentAdornment added, CommentAdornment removed)
        {
            this.CommentAdded = added;
            this.CommentRemoved = removed;
        }
    }
    

주석 장식 관리

주석 장식 관리자는 장식 만들어 장식 레이어를 추가 합니다. 수신 하는 LayoutChangedClosed 하 여 이동 하거나 삭제는 장식 수 있습니다 이벤트. 하도 수신은 CommentsChanged 메모를 추가 하거나 제거 하면 주석 장식 공급자에 의해 발생 하는 이벤트입니다.

주석 장식 관리 하기

  1. CommentAdornmentTest 프로젝트에 클래스 파일을 추가 하 고 이름을 CommentAdornmentManager.

  2. 다음 추가 using 문입니다.

    Imports System
    Imports System.Collections.Generic
    Imports System.Windows.Media
    Imports Microsoft.VisualStudio.Text
    Imports Microsoft.VisualStudio.Text.Editor
    Imports Microsoft.VisualStudio.Text.Formatting
    
    using System;
    using System.Collections.Generic;
    using System.Windows.Media;
    using Microsoft.VisualStudio.Text;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Text.Formatting;
    
  3. 라는 클래스를 추가 합니다. CommentAdornmentManager.

    Friend Class CommentAdornmentManager
    
    internal class CommentAdornmentManager
    
  4. Private 필드를 추가 합니다.

    Private ReadOnly view As IWpfTextView
    Private ReadOnly layer As IAdornmentLayer
    Private ReadOnly provider As CommentAdornmentProvider
    
    private readonly IWpfTextView view;
    private readonly IAdornmentLayer layer;
    private readonly CommentAdornmentProvider provider;
    
  5. 관리자에 등록 되는 생성자를 추가 LayoutChangedClosed 이벤트, 뿐만 아니라는 CommentsChanged 이벤트입니다. 관리자가 정적 인스턴스화되므로 생성자가 private이 Create() 메서드가 있습니다.

    Private Sub New(ByVal view As IWpfTextView)
        Me.view = view
        AddHandler Me.view.LayoutChanged, AddressOf OnLayoutChanged
        AddHandler Me.view.Closed, AddressOf OnClosed
    
        Me.layer = view.GetAdornmentLayer("CommentAdornmentLayer")
    
        Me.provider = CommentAdornmentProvider.Create(view)
        AddHandler Me.provider.CommentsChanged, AddressOf OnCommentsChanged
    End Sub
    
    private CommentAdornmentManager(IWpfTextView view)
    {
        this.view = view;
        this.view.LayoutChanged += OnLayoutChanged;
        this.view.Closed += OnClosed;
    
        this.layer = view.GetAdornmentLayer("CommentAdornmentLayer");
    
        this.provider = CommentAdornmentProvider.Create(view);
        this.provider.CommentsChanged += OnCommentsChanged;
    }
    
  6. 추가 Create() 메서드는 공급자를 가져오거나 필요한 경우 그룹을 만듭니다.

    Public Shared Function Create(ByVal view As IWpfTextView) As CommentAdornmentManager
        Return view.Properties.GetOrCreateSingletonProperty(Of CommentAdornmentManager)(Function() New CommentAdornmentManager(view))
    End Function
    
    public static CommentAdornmentManager Create(IWpfTextView view)
    {
        return view.Properties.GetOrCreateSingletonProperty<CommentAdornmentManager>(delegate { return new CommentAdornmentManager(view); });
    }
    
  7. 추가 CommentsChanged 처리기입니다.

    Private Sub OnCommentsChanged(ByVal sender As Object, ByVal e As CommentsChangedEventArgs)
        'Remove the comment (when the adornment was added, the comment adornment was used as the tag). 
        If e.CommentRemoved IsNot Nothing Then 
            Me.layer.RemoveAdornmentsByTag(e.CommentRemoved)
        End If 
    
        'Draw the newly added comment (this will appear immediately: the view does not need to do a layout). 
        If e.CommentAdded IsNot Nothing Then 
            Me.DrawComment(e.CommentAdded)
        End If 
    End Sub
    
    private void OnCommentsChanged(object sender, CommentsChangedEventArgs e)
    {
        //Remove the comment (when the adornment was added, the comment adornment was used as the tag). 
        if (e.CommentRemoved != null)
            this.layer.RemoveAdornmentsByTag(e.CommentRemoved);
    
        //Draw the newly added comment (this will appear immediately: the view does not need to do a layout). 
        if (e.CommentAdded != null)
            this.DrawComment(e.CommentAdded);
    }
    
  8. 추가 Closed 처리기입니다.

    Private Sub OnClosed(ByVal sender As Object, ByVal e As EventArgs)
        Me.provider.Detach()
        RemoveHandler Me.view.LayoutChanged, AddressOf OnLayoutChanged
        RemoveHandler Me.view.Closed, AddressOf OnClosed
    End Sub
    
    private void OnClosed(object sender, EventArgs e)
    {
        this.provider.Detach();
        this.view.LayoutChanged -= OnLayoutChanged;
        this.view.Closed -= OnClosed;
    }
    
  9. 추가 LayoutChanged 처리기입니다.

    Private Sub OnLayoutChanged(ByVal sender As Object, ByVal e As TextViewLayoutChangedEventArgs)
        'Get all of the comments that intersect any of the new or reformatted lines of text. 
        Dim newComments As New List(Of CommentAdornment)()
    
        'The event args contain a list of modified lines and a NormalizedSpanCollection of the spans of the modified lines.  
        'Use the latter to find the comments that intersect the new or reformatted lines of text. 
        For Each span As Span In e.NewOrReformattedSpans
            newComments.AddRange(Me.provider.GetComments(New SnapshotSpan(Me.view.TextSnapshot, span)))
        Next span
    
        'It is possible to get duplicates in this list if a comment spanned 3 lines, and the first and last lines were modified but the middle line was not. 
        'Sort the list and skip duplicates.
        newComments.Sort(Function(a As CommentAdornment, b As CommentAdornment) a.GetHashCode().CompareTo(b.GetHashCode()))
    
        Dim lastComment As CommentAdornment = Nothing 
        For Each comment As CommentAdornment In newComments
            If comment IsNot lastComment Then
                lastComment = comment
                Me.DrawComment(comment)
            End If 
        Next comment
    End Sub
    
    private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
    {
        //Get all of the comments that intersect any of the new or reformatted lines of text.
        List<CommentAdornment> newComments = new List<CommentAdornment>();
    
        //The event args contain a list of modified lines and a NormalizedSpanCollection of the spans of the modified lines.  
        //Use the latter to find the comments that intersect the new or reformatted lines of text. 
        foreach (Span span in e.NewOrReformattedSpans)
        {
            newComments.AddRange(this.provider.GetComments(new SnapshotSpan(this.view.TextSnapshot, span)));
        }
    
        //It is possible to get duplicates in this list if a comment spanned 3 lines, and the first and last lines were modified but the middle line was not. 
        //Sort the list and skip duplicates.
        newComments.Sort(delegate(CommentAdornment a, CommentAdornment b) { return a.GetHashCode().CompareTo(b.GetHashCode()); });
    
        CommentAdornment lastComment = null;
        foreach (CommentAdornment comment in newComments)
        {
            if (comment != lastComment)
            {
                lastComment = comment;
                this.DrawComment(comment);
            }
        }
    }
    
  10. 주석을 그립니다 전용 메서드를 추가 합니다.

    Private Sub DrawComment(ByVal comment As CommentAdornment)
        Dim span As SnapshotSpan = comment.Span.GetSpan(Me.view.TextSnapshot)
        Dim g As Geometry = Me.view.TextViewLines.GetMarkerGeometry(span)
    
        If g IsNot Nothing Then 
            'Find the rightmost coordinate of all the lines that intersect the adornment. 
            Dim maxRight As Double = 0.0
            For Each line As ITextViewLine In Me.view.TextViewLines.GetTextViewLinesIntersectingSpan(span)
                maxRight = Math.Max(maxRight, line.Right)
            Next line
    
            'Create the visualization. 
            Dim block As New CommentBlock(maxRight, Me.view.ViewportRight, g, comment.Author, comment.Text)
    
            'Add it to the layer. 
            Me.layer.AddAdornment(span, comment, block)
        End If 
    End Sub
    
    private void DrawComment(CommentAdornment comment)
    {
        SnapshotSpan span = comment.Span.GetSpan(this.view.TextSnapshot);
        Geometry g = this.view.TextViewLines.GetMarkerGeometry(span);
    
        if (g != null)
        {
            //Find the rightmost coordinate of all the lines that intersect the adornment. 
            double maxRight = 0.0;
            foreach (ITextViewLine line in this.view.TextViewLines.GetTextViewLinesIntersectingSpan(span))
                maxRight = Math.Max(maxRight, line.Right);
    
            //Create the visualization.
            CommentBlock block = new CommentBlock(maxRight, this.view.ViewportRight, g, comment.Author, comment.Text);
    
            //Add it to the layer. 
            this.layer.AddAdornment(span, comment, block);
        }
    }
    

이 메뉴 명령을 사용 하 여 주석 장식 추가

메뉴 명령을 사용 하 여 주석 장식 구현 하 여 만들 수 있는 MenuItemCallback 메서드는 VSPackage 합니다.

메뉴 명령을 사용 하 여 주석 장식 추가 하기

  1. MenuCommandTest 프로젝트에 다음 참조를 추가 합니다.

    • Microsoft.VisualStudio.TextManager.Interop

    • Microsoft.VisualStudio.Editor

    • Microsoft.VisualStudio.Text.UI.Wpf

  2. CommentAdornmentTest 프로젝트에 참조를 추가 합니다.

  3. MenuCommandTestPackage 파일을 엽니다.

  4. 다음 추가 using 문입니다.

    Imports Microsoft.VisualStudio.TextManager.Interop
    Imports Microsoft.VisualStudio.Text.Editor
    Imports Microsoft.VisualStudio.Editor
    Imports CommentAdornmentTest
    
    using Microsoft.VisualStudio.TextManager.Interop;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Editor;
    using CommentAdornmentTest;
    
  5. 에 있는 MenuItemCallback 메서드를 기존 코드를 제거 합니다.

  6. 현재 보기를 표시 하는 코드를 추가 합니다. 가져와야 합니다는 SVsTextManager Visual Studio 셸의 활성 얻을 수 IVsTextView.

    Dim txtMgr As IVsTextManager = CType(GetService(GetType(SVsTextManager)), IVsTextManager)
    Dim vTextView As IVsTextView = Nothing 
    Dim mustHaveFocus As Integer = 1
    txtMgr.GetActiveView(mustHaveFocus, Nothing, vTextView)
    
    IVsTextManager txtMgr = (IVsTextManager)GetService(typeof(SVsTextManager));
    IVsTextView vTextView = null;
    int mustHaveFocus = 1;
    txtMgr.GetActiveView(mustHaveFocus, null, out vTextView);
    
  7. 이 텍스트는 편집기의 텍스트 보기의 인스턴스 보기인 경우에 캐스팅할 수 있습니다는 IVsUserData 인터페이스 하 고는 IWpfTextViewHost 및 해당 연결 된 IWpfTextView.

    Dim userData As IVsUserData = TryCast(vTextView, IVsUserData)
    If userData Is Nothing Then
        Console.WriteLine("No text view is currently open")
        Return 
    End If 
    Dim viewHost As IWpfTextViewHost
    Dim holder As Object 
    Dim guidViewHost As Guid = DefGuidList.guidIWpfTextViewHost
    userData.GetData(guidViewHost, holder)
    viewHost = CType(holder, IWpfTextViewHost)
    
    IVsUserData userData = vTextView as IVsUserData;
    if (userData == null)
    {
        Console.WriteLine("No text view is currently open");
        return;
    }
    IWpfTextViewHost viewHost;
    object holder;
    Guid guidViewHost = DefGuidList.guidIWpfTextViewHost;
    userData.GetData(ref guidViewHost, out holder);
    viewHost = (IWpfTextViewHost)holder;
    
  8. 사용의 IWpfTextViewHost 를 호출 하는 Connector.Execute() 메서드를 주석 장식 공급자 가져오고 있는 장식 추가 합니다.

    Connector.Execute(viewHost)
    
    Connector.Execute(viewHost);
    

빌드 및 코드 테스트

이 코드를 테스트 하려면 메뉴 명령 솔루션을 빌드하고 실험 인스턴스를 실행 합니다.

빌드 및 테스트 메뉴 명령 솔루션을

  1. 솔루션을 빌드합니다. 이 프로젝트를 디버거에서 실행할 때 Visual Studio 두 번째 인스턴스를 인스턴스화합니다.

  2. 텍스트 파일을 만듭니다. 일부 텍스트를 입력 한 다음 선택 합니다.

  3. 에 있는 도구 메뉴를 클릭 추가 장식. 풍선 도움말 텍스트 창의 오른쪽에 표시 되 고 다음 텍스트와 비슷한 텍스트가 포함 되어야 합니다.

    YourUserName

    Fourscore…

참고 항목

작업

연습: 콘텐츠 형식의 파일 이름 확장명에 연결