Condividi tramite


procedura dettagliata: Utilizzando un comando della shell con un'estensione dell'editor

Da un package VS, è possibile aggiungere funzionalità quali comandi di menu all'editor. In questa procedura dettagliata viene illustrato come aggiungere un ornamento a una visualizzazione di testo nell'editor richiamando un comando di menu.

In questa procedura dettagliata viene illustrato l'utilizzo di un package VS insieme a una parte gestita della parte (MEF) del Framework di estensibilità. È necessario utilizzare un VSPackage per registrare il comando di menu con la shell di Visual Studio ed è possibile utilizzare il comando per accedere alla parte del componente MEF.

Prerequisiti

Per completare questa procedura dettagliata, è necessario installare Visual Studio 2010 SDK.

Nota

per ulteriori informazioni su Visual Studio SDK, vedere Cenni preliminari sull'estensione di Visual Studio.Per ulteriori informazioni su come scaricare Visual Studio SDK, vedere Centro per sviluppatori di estensibilità di Visual Studio il sito Web MSDN.

Posizioni del modello di progetto del pacchetto Visual Studio

Il modello di progetto del pacchetto Visual Studio è disponibile in tre posizioni diverse nella finestra di dialogo di nuovo progetto :

  1. Sotto di estensibilità di Visual Basic. La lingua predefinita del progetto di Visual Basic.

  2. Sotto di estensibilità di c#. La lingua predefinita del progetto è c#.

  3. Nell'ambito dell'altra estensibilità dei tipi di progetto. La lingua predefinita del progetto è C++

creare un comando di menu VSPackage

Creare un package VS che inserisce un comando di menu denominato Aggiungere l'area di controllo scegliere dal menu di strumenti .

Per creare un comando di menu VSPackage

  1. Creare un pacchetto Visual Studio e denominarlo MenuCommandTest. Scegliere OK.

  2. Nella pagina di benvenuto, fare clic su dopo.

  3. Nella pagina di selezionare un linguaggio di programmazione , Visual Basic selezionato o Visual C#, assicurarsi che generare un nuovo file di chiave per firmare l'assembly sia selezionato e quindi fare clic su dopo.

  4. Nella pagina di Informazioni di base di un VSPackage , in Nome di un VSPackageMenuCommandla casella digitare e quindi fare clic dopo.

  5. Nella pagina di Selezionare le opzioni di package VS , comando di menu quindi fare clic su dopo.

  6. Nella pagina di Opzioni del comando , in Nome del comandoAggiungere l'area di controllola casella digitare. Nella casella di ID di comando , tipo cmdidAddAdornment. Scegliere Avanti.

  7. Nella pagina di Selezionare le opzioni di test , deselezionare entrambe le opzioni e quindi fare clic - Fine.

  8. una soluzione denominata MenuCommandTest è aperta. Il file di MenuCommandTestPackage il codice che crea il comando di menu e lo inserisce nel menu di strumenti . In questa fase, il comando fa sì che solo una finestra di messaggio. I passaggi successivi viene illustrato come modificare questo per visualizzare l'area di controllo del commento.

  9. Aprire il file source.extension.vsixmanifest nell'editor del manifesto VSIX. Deve avere una riga di Content per un VSPackage denominato MenuCommand.

  10. Salvare e chiudere il file Source.extension.vsixmanifest.

Aggiunta di un'estensione MEF alla soluzione di package VS

Per aggiungere l'estensione MEF alla soluzione di package VS

  1. In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo della soluzione, scegliere Aggiungi, quindi Nuovo progetto. Nella finestra di dialogo di aggiungere il nuovo progetto , nell'estensibilità di scegliere in Visual Basic o in Visual C#, quindi EditorClassifier. denominare il progetto CommentAdornmentTest.

  2. Poiché questo progetto interagirà con l'assembly con nome sicuro di un VSPackage, è necessario firmare l'assembly. È possibile riutilizzare il file di chiave già creato per l'assembly di un VSPackage.

    1. Aprire le proprietà del progetto e selezionare la pagina di firma .

    2. selezionare firmare l'assembly.

    3. In Scegliere un file di chiave con nome sicuro, selezionare il file Key.snk generato per l'assembly di MenuCommandTest.

    4. Salvare il progetto.

Fare riferimento all'estensione MEF nel progetto VSPackage

Poiché si sta aggiungendo un componente MEF al package VS, è necessario specificare entrambi i tipi di contenuto nel manifesto.

Nota

Per ulteriori informazioni su MEF, vedere Managed Extensibility Framework (MEF).

Per fare riferimento al componente MEF nel package VS progetto

  1. Nel progetto MenuCommandTest, aprire il file source.extension.vsixmanifest nell'editor del manifesto VSIX.

  2. In contenuto e dirette, fare clic Aggiungere contenuto. Nell'elenco di selezionare il tipo di contenuto , Componente MEFselezionato. In selezionare un database di origine, CommentAdornmentTestselezionato.

  3. Salvare e chiudere il file source.extension.vsixmanifest.

  4. Aggiungere un riferimento al progetto CommentAdornmentTest.

Definizione dell'area di commento

L'area di controllo stesso di commento è costituito da ITrackingSpan che tiene traccia del testo selezionato e alcune stringhe che rappresentano l'autore e la descrizione del testo.

Per definire un ornamento di commento

  1. Nel progetto CommentAdornmentTest, eliminare i file di classe esistenti.

  2. Aggiungere un nuovo file di classe e denominarlo CommentAdornment.

  3. Aggiungere l'istruzione riportata di using .

    Imports Microsoft.VisualStudio.Text
    
    using Microsoft.VisualStudio.Text;
    
  4. Aggiungere CommentAdornmentclasse denominata.

    Friend Class CommentAdornment
    
    internal class CommentAdornment
    
  5. Aggiungere tre campi alla classe di CommentAdornment per ITrackingSpan, l'autore e la descrizione.

    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. Aggiungere un costruttore per inizializzare i campi.

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

Creare un elemento visivo per l'area di controllo

È inoltre necessario definire un elemento visivo per l'area di controllo. Per questa procedura dettagliata, definire un controllo che eredita dalla classe (WPF) Canvasdi Windows Presentation Foundation.

Per creare un elemento visivo per l'area di controllo

  1. Creare una classe nel progetto CommentAdornmentTest e denominarla CommentBlock.

  2. Aggiungere le seguenti istruzioni di 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. Impostare la classe di CommentBlock ereditare da Canvas.

    Friend Class CommentBlock
        Inherits Canvas
    
    internal class CommentBlock : Canvas
    
  4. Aggiungere alcuni campi privati per definire gli aspetti visivi dell'area di controllo.

    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. Aggiungere un costruttore che definisce l'area di controllo di commento e aggiunge il testo rilevante.

    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. Inoltre implementare un gestore eventi di OnRender che consente di disegnare l'area di controllo.

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

Aggiunta di IWpfTextViewCreationListener

IWpfTextViewCreationListener è un elemento del framework MEF che è possibile utilizzare per rimanere in ascolto per visualizzare gli eventi di creazione.

Per aggiungere un IWpfTextViewCreationListener

  1. Aggiungere il file di classe Al progetto CommentAdornmentTest e denominarlo connettore.

  2. Aggiungere le seguenti istruzioni di 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. Dichiarare una classe che implementa IWpfTextViewCreationListener ed esportarla con ContentTypeAttribute di “testo„ e TextViewRoleAttribute di Document. L'attributo di tipo di contenuto specifica il tipo di contenuto sul quale il componente viene applicato. Il tipo di testo è il tipo di base per tutti i tipi di file non di binario. Di conseguenza, quasi ogni visualizzazione di testo che viene creata sarà di questo tipo. Dell'attributo di ruoli della visualizzazione di testo specifica il tipo di visualizzazione di testo a cui il componente viene applicato. Ruoli del testo di visualizzazione della visualizzazione di testo documento che si compone di righe e viene archiviato in un file.

    <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. Implementare il metodo di TextViewCreated in modo che venga chiamato l'evento statico di Create() di 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. Aggiungere un metodo che consente di eseguire il comando.

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

Definizione del livello dell'area di controllo

Per aggiungere un nuovo area di controllo, è necessario definire un livello dell'area di controllo.

Per definire un livello dell'area di controllo

  • Nella classe di Connector dichiarare un campo pubblico di tipo AdornmentLayerDefinition e esportarlo con NameAttribute che specifica un nome univoco per il livello e area OrderAttribute che definisce la relazione di ordine Z tra il livello dell'area di controllo e gli altri livelli della visualizzazione di testo (testo, cursore e selezione).

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

Fornire gli attributi di commento

Quando si definisce un'area di controllo, inoltre implementare un provider dell'area di commento e un amministratore area di commento. Il provider dell'area di commento mantiene un elenco delle aree di controllo di commento, è in ascolto degli eventi di Changed nel buffer di testo sottostante e gli attributi di commento elimina quando il testo sottostante viene eliminato.

Per aggiungere il provider dell'area di commento

  1. Aggiungere un nuovo file di classe al progetto CommentAdornmentTest e denominarlo CommentAdornmentProvider.

  2. Aggiungere le seguenti istruzioni di 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. Aggiungere CommentAdornmentProviderclasse denominata.

    Friend Class CommentAdornmentProvider
    
    internal class CommentAdornmentProvider
    
  4. Aggiungere campi privati per il buffer di testo e l'elenco delle aree di controllo dei commenti relativi al buffer.

    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. aggiungere un costruttore per CommentAdornmentProvider. Questo costruttore deve avere accesso privato perché il provider viene creata un'istanza con il metodo di Create() . Il costruttore viene aggiunto il gestore eventi di OnBufferChanged all'evento di 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. aggiungere il metodo di 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. aggiungere il metodo di 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. aggiungere il gestore eventi di 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. Aggiungere una dichiarazione per l'evento di CommentsChanged .

    Public Event CommentsChanged As EventHandler(Of CommentsChangedEventArgs)
    
    public event EventHandler<CommentsChangedEventArgs> CommentsChanged;
    
  10. Creare un metodo di Add() per aggiungere l'area di controllo.

    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. Aggiungere un metodo 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. Aggiungere un metodo di GetComments() che restituisce tutti i commenti in un intervallo dello snapshot specificato.

    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. Aggiungere CommentsChangedEventArgsclasse denominata, come illustrato di seguito.

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

Gestire gli attributi di commento

L'amministratore area di commento viene creata l'area di controllo e lo aggiunge a livello dell'area di controllo. È in ascolto degli eventi di Closed e di LayoutChanged in modo da poter spostare o eliminare l'area di controllo. Anche ascolta l'evento di CommentsChanged generato dal provider dell'area di commento quando i commenti aggiunti o rimossi.

Per gestire gli attributi di commento

  1. Aggiungere il file di classe Al progetto CommentAdornmentTest e denominarlo CommentAdornmentManager.

  2. Aggiungere le seguenti istruzioni di 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. Aggiungere CommentAdornmentManagerclasse denominata.

    Friend Class CommentAdornmentManager
    
    internal class CommentAdornmentManager
    
  4. aggiungere alcuni campi privati.

    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. Aggiungere un costruttore che sottoscrive gestione degli eventi di Closed e di LayoutChanged e anche all'evento di CommentsChanged . Il costruttore è privato perché il gestore viene creata un'istanza con il metodo statico di 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. Aggiungere il metodo di Create() che ottiene un provider o ne crea uno su richiesta.

    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. aggiungere il gestore di 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. aggiungere il gestore di 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. aggiungere il gestore di 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. aggiungere il metodo privato che disegna il commento.

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

Utilizzando il comando di menu aggiungere l'area di controllo di commento

È possibile utilizzare il comando di menu creare un ornamento di commento implementando il metodo di MenuItemCallback del package VS.

Per utilizzare il comando di menu aggiungere l'area di controllo di commento

  1. Aggiungere i seguenti riferimenti al progetto MenuCommandTest:

    • Microsoft.VisualStudio.TextManager.Interop

    • Microsoft.VisualStudio.Editor

    • Microsoft.VisualStudio.Text.UI.Wp f

  2. Aggiungere un riferimento al progetto CommentAdornmentTest.

  3. aprire il file di MenuCommandTestPackage.

  4. Aggiungere le seguenti istruzioni di 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. Nel metodo di MenuItemCallback , rimuovere il codice esistente.

  6. aggiungere il codice per ottenere la visualizzazione attiva. È necessario ottenere SVsTextManager shell di Visual Studio per ottenere IVsTextViewattivo.

    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. Se questa visualizzazione di testo è un'istanza di una visualizzazione di testo dell'editor, è possibile eseguirne il cast all'interfaccia di IVsUserData e ottenere IWpfTextViewHost e il relativo IWpfTextViewassociato.

    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. Utilizzare IWpfTextViewHost per chiamare il metodo di Connector.Execute() , che ottiene il provider dell'area di commento e aggiunge l'area di controllo.

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

Compilazione e test del codice

Per testare questo codice, compilare la soluzione di MenuCommand ed eseguirla nell'istanza sperimentale.

Per compilare e testare la soluzione di MenuCommand

  1. Compilare la soluzione. Quando si esegue il progetto nel debugger, una seconda istanza di Visual Studio viene creata un'istanza.

  2. Creare un file di testo. Digitare un testo e selezionarlo.

  3. Scegliere dal menu di strumenti , fare clic Aggiungere l'area di controllo. Un'area commenti deve essere visualizzato sul lato destro della finestra di testo e deve contenere il testo analogo al seguente testo.

    TheUserName

    Fourscore…

Vedere anche

Attività

procedura dettagliata: Collegare un tipo di contenuto a un'estensione di file