Freigeben über


Exemplarische Vorgehensweise: Verwenden eines Shellbefehls mit einer Editorerweiterung

Über ein VSPackage können Sie dem Editor Features wie Menübefehle hinzufügen. In dieser exemplarischen Vorgehensweise wird gezeigt, wie Sie einer Textansicht im Editor ein Zierzeichen hinzufügen, indem Sie einen Menübefehl aufrufen.

In dieser exemplarischen Vorgehensweise wird die Verwendung eines VSPackage zusammen mit einem MEF-Komponententeil (Managed Extensibility Framework) veranschaulicht. Sie müssen ein VSPackage verwenden, um den Menübefehl mit der Visual Studio-Shell zu registrieren. Außerdem können Sie den Befehl verwenden, um auf den MEF-Komponententeil zuzugreifen.

Erstellen einer Erweiterung mit einem Menübefehl

Erstellen Sie eine VSPackage, die einen Menübefehl mit dem Namen "Schmücken hinzufügen" im Menü "Extras " platziert.

  1. Erstellen Sie ein C#VSIX-Projekt mit dem Namen MenuCommandTest"AddAdornment", und fügen Sie den Namen einer benutzerdefinierten Befehlselementvorlage hinzu. Weitere Informationen finden Sie unter Erstellen einer Erweiterung mit einem Menübefehl.

  2. Eine Lösung mit dem Namen MenuCommandTest wird geöffnet. Die MenuCommandTestPackage-Datei enthält den Code, der den Menübefehl erstellt und im Menü "Extras " platziert. An diesem Punkt bewirkt der Befehl nur, dass ein Meldungsfeld angezeigt wird. In späteren Schritten wird gezeigt, wie Sie dies ändern können, um das Kommentarzieren anzuzeigen.

  3. Öffnen Sie die Datei "source.extension.vsixmanifest " im VSIX-Manifest-Editor. Die Assets Registerkarte sollte eine Zeile für ein "Microsoft.VisualStudio.VsPackage" mit dem Namen "MenuCommandTest" aufweisen.

  4. Speichern und schließen Sie die Datei "source.extension.vsixmanifest ".

Hinzufügen einer MEF-Erweiterung zur Befehlserweiterung

  1. Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf den Projektmappenknoten, klicken Sie auf "Hinzufügen", und klicken Sie dann auf "Neues Projekt". Klicken Sie im Dialogfeld "Neues Projekt hinzufügen" unter Visual C# auf "Erweiterbarkeit" und dann auf "VSIX Project". Benennen Sie das Projekt mit CommentAdornmentTest.

  2. Da dieses Projekt mit der stark benannten VSPackage-Assembly interagiert, müssen Sie die Assembly signieren. Sie können die schlüsseldatei wiederverwenden, die bereits für die VSPackage-Assembly erstellt wurde.

    1. Öffnen Sie die Projekteigenschaften, und wählen Sie die Registerkarte "Signieren" aus .

    2. Wählen Sie " Assembly signieren" aus.

    3. Wählen Sie unter "Schlüsseldatei mit starkem Namen" die Datei "Key.snk " aus, die für die MenuCommandTest-Assembly generiert wurde.

Verweisen auf die MEF-Erweiterung im VSPackage-Projekt

Da Sie eine MEF-Komponente zum VSPackage hinzufügen, müssen Sie beide Arten von Ressourcen im Manifest angeben.

Hinweis

Weitere Informationen zu MEF finden Sie unter Managed Extensibility Framework (MEF).

So verweisen Sie auf die MEF-Komponente im VSPackage-Projekt

  1. Öffnen Sie im MenuCommandTest-Projekt die Datei "source.extension.vsixmanifest " im VSIX-Manifest-Editor.

  2. Klicken Sie auf der Registerkarte "Objekte " auf "Neu".

  3. Wählen Sie in der Liste Typ den Eintrag Microsoft.VisualStudio.MefComponent aus.

  4. Wählen Sie in der Liste Quelle die Option Ein Projekt in der aktuellen Projektmappe aus.

  5. Wählen Sie in der Projektliste "CommentAdornmentTest" aus.

  6. Speichern und schließen Sie die Datei "source.extension.vsixmanifest ".

  7. Stellen Sie sicher, dass das MenuCommandTest-Projekt über einen Verweis auf das CommentAdornmentTest-Projekt verfügt.

  8. Legen Sie im CommentAdornmentTest-Projekt das Projekt so fest, dass eine Assembly erstellt wird. Wählen Sie im Projektmappen-Explorer das Projekt aus, und suchen Sie im Fenster "Eigenschaften" nach der Eigenschaft "Buildausgabe in OutputDirectory kopieren", und legen Sie es auf "true" fest.

Definieren einer Kommentarzierung

Das Kommentarzieren selbst besteht aus einem ITrackingSpan , der den markierten Text verfolgt, und einige Zeichenfolgen, die den Autor und die Beschreibung des Texts darstellen.

So definieren Sie ein Kommentarzieren

  1. Fügen Sie im CommentAdornmentTest-Projekt eine neue Klassendatei hinzu, und nennen Sie sie CommentAdornment.

  2. Fügen Sie die folgenden Verweise hinzu:

    1. Microsoft.VisualStudio.CoreUtility

    2. Microsoft.VisualStudio.Text.Data

    3. Microsoft.VisualStudio.Text.Logic

    4. Microsoft.VisualStudio.Text.UI

    5. Microsoft.VisualStudio.Text.UI.Wpf

    6. System.ComponentModel.Composition

    7. PresentationCore

    8. PresentationFramework

    9. WindowsBase

  3. Fügen Sie die folgende using Direktive hinzu.

    using Microsoft.VisualStudio.Text;
    
  4. Die Datei sollte eine Klasse mit dem Namen CommentAdornmententhalten.

    internal class CommentAdornment
    
  5. Fügen Sie der Klasse für den CommentAdornmentITrackingSpan, den Autor und die Beschreibung drei Felder hinzu.

    public readonly ITrackingSpan Span;
    public readonly string Author;
    public readonly string Text;
    
  6. Fügen Sie einen Konstruktor hinzu, der die Felder initialisiert.

    public CommentAdornment(SnapshotSpan span, string author, string text)
    {
        this.Span = span.Snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeExclusive);
        this.Author = author;
        this.Text = text;
    }
    

Erstellen eines visuellen Elements für die Dekoration

Definieren Sie ein visuelles Element für Ihre Dekoration. Definieren Sie für diese exemplarische Vorgehensweise ein Steuerelement, das von der Windows Presentation Foundation (WPF)-Klasse Canvaserbt.

  1. Erstellen Sie eine Klasse im CommentAdornmentTest-Projekt, und nennen Sie sie CommentBlock.

  2. Fügen Sie die folgenden using Direktiven hinzu.

    using Microsoft.VisualStudio.Text;
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Shapes;
    using System.ComponentModel.Composition;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Utilities;
    
  3. Übernehmen Sie die CommentBlock Klasse von Canvas.

    internal class CommentBlock : Canvas
    { }
    
  4. Fügen Sie einige private Felder hinzu, um die visuellen Aspekte der Verzierung zu definieren.

    private Geometry textGeometry;
    private Grid commentGrid;
    private static Brush brush;
    private static Pen solidPen;
    private static Pen dashPen;
    
  5. Fügen Sie einen Konstruktor hinzu, der die Kommentarzierer definiert, und fügt den relevanten Text hinzu.

    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. Implementieren Sie auch einen OnRender Ereignishandler, der die Dekoration zeichnet.

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

Hinzufügen eines IWpfTextViewCreationListener

Dies IWpfTextViewCreationListener ist ein MEF-Komponententeil, den Sie zum Überwachen von Erstellungsereignissen verwenden können.

  1. Fügen Sie dem CommentAdornmentTest-Projekt eine Klassendatei hinzu, und nennen Sie sie Connector.

  2. Fügen Sie die folgenden using Direktiven hinzu.

    using System.ComponentModel.Composition;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Utilities;
    
  3. Deklarieren Sie eine Klasse, die sie implementiert IWpfTextViewCreationListener, und exportieren Sie sie mit einem ContentTypeAttribute "Text" und einem TextViewRoleAttribute von Document. Das Inhaltstyp-Attribut gibt die Art des Inhalts an, auf den die Komponente angewendet wird. Der Texttyp ist der Basistyp für alle nicht binären Dateitypen. Daher wird fast jede textansicht, die erstellt wird, von diesem Typ sein. Das Rollenattribute für die Textansicht gibt die Art der Textansicht an, auf die die Komponente angewendet wird. Dokumenttextansichtsrollen zeigen in der Regel Text an, der aus Zeilen besteht und in einer Datei gespeichert wird.

    [Export(typeof(IWpfTextViewCreationListener))]
    [ContentType("text")]
    [TextViewRole(PredefinedTextViewRoles.Document)]
    public sealed class Connector : IWpfTextViewCreationListener
    
  4. Implementieren Sie die TextViewCreated Methode, sodass sie das statische Create() Ereignis des CommentAdornmentManager.

    public void TextViewCreated(IWpfTextView textView)
    {
        CommentAdornmentManager.Create(textView);
    }
    
  5. Fügen Sie eine Methode hinzu, mit der Sie den Befehl ausführen können.

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

Definieren einer Schmückenebene

Um ein neues Zierelement hinzuzufügen, müssen Sie eine Verzierungsebene definieren.

So definieren Sie eine Schmückenebene

  1. Deklarieren Sie in der Connector Klasse ein öffentliches Feld vom Typ AdornmentLayerDefinition, und exportieren Sie es mit einem NameAttribute , der einen eindeutigen Namen für die Verzierungsebene angibt, und eine OrderAttribute , die die Z-Reihenfolge-Beziehung dieser Verzierungsebene zu den anderen Textansichtsebenen (Text, Caret und Auswahl) definiert.

    [Export(typeof(AdornmentLayerDefinition))]
    [Name("CommentAdornmentLayer")]
    [Order(After = PredefinedAdornmentLayers.Selection, Before = PredefinedAdornmentLayers.Text)]
    public AdornmentLayerDefinition commentLayerDefinition;
    
    

Bereitstellen von Kommentarzieren

Wenn Sie ein Zierelement definieren, implementieren Sie auch einen Kommentarzieranbieter und einen Kommentarzierer. Der Kommentarzieranbieter behält eine Liste mit Kommentarzierern bei, lauscht Changed auf Ereignisse im zugrunde liegenden Textpuffer und löscht Kommentare, wenn der zugrunde liegende Text gelöscht wird.

  1. Fügen Sie dem CommentAdornmentTest-Projekt eine neue Klassendatei hinzu, und nennen Sie sie CommentAdornmentProvider.

  2. Fügen Sie die folgenden using Direktiven hinzu.

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using Microsoft.VisualStudio.Text;
    using Microsoft.VisualStudio.Text.Editor;
    
  3. Fügen Sie eine Klasse namens CommentAdornmentProviderhinzu.

    internal class CommentAdornmentProvider
    {
    }
    
  4. Fügen Sie private Felder für den Textpuffer und die Liste der Kommentarzierer im Zusammenhang mit dem Puffer hinzu.

    private ITextBuffer buffer;
    private IList<CommentAdornment> comments = new List<CommentAdornment>();
    
    
  5. Fügen Sie einen Konstruktor für CommentAdornmentProvider. Dieser Konstruktor sollte über privaten Zugriff verfügen, da der Anbieter von der Create() Methode instanziiert wird. Der Konstruktor fügt dem Ereignis den OnBufferChanged Ereignishandler hinzu Changed .

    private CommentAdornmentProvider(ITextBuffer buffer)
    {
        this.buffer = buffer;
        //listen to the Changed event so we can react to deletions. 
        this.buffer.Changed += OnBufferChanged;
    }
    
    
  6. Fügen Sie die Create()-Methode hinzu.

    public static CommentAdornmentProvider Create(IWpfTextView view)
    {
        return view.Properties.GetOrCreateSingletonProperty<CommentAdornmentProvider>(delegate { return new CommentAdornmentProvider(view.TextBuffer); });
    }
    
    
  7. Fügen Sie die Detach()-Methode hinzu.

    public void Detach()
    {
        if (this.buffer != null)
        {
            //remove the Changed listener 
            this.buffer.Changed -= OnBufferChanged;
            this.buffer = null;
        }
    }
    
  8. Fügen Sie den OnBufferChanged Ereignishandler hinzu.

    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. Fügen Sie eine Deklaration für ein CommentsChanged Ereignis hinzu.

    public event EventHandler<CommentsChangedEventArgs> CommentsChanged;
    
  10. Erstellen Sie eine Add() Methode, um das Zierelement hinzuzufügen.

    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. Fügen Sie eine RemoveComments() Methode hinzu.

    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. Fügen Sie eine GetComments() Methode hinzu, die alle Kommentare in einer bestimmten Momentaufnahme Spanne zurückgibt.

    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. Fügen Sie wie folgt eine Klasse mit dem Namen CommentsChangedEventArgshinzu.

    internal class CommentsChangedEventArgs : EventArgs
    {
        public readonly CommentAdornment CommentAdded;
    
        public readonly CommentAdornment CommentRemoved;
    
        public CommentsChangedEventArgs(CommentAdornment added, CommentAdornment removed)
        {
            this.CommentAdded = added;
            this.CommentRemoved = removed;
        }
    }
    

Verwalten von Kommentarzierzierungen

Der Kommentarziermanager erstellt das Zierelement und fügt es der Verzierungsebene hinzu. Es lauscht auf die LayoutChanged und Closed Ereignisse, damit es die Dekoration verschieben oder löschen kann. Außerdem lauscht es auf das CommentsChanged Ereignis, das vom Kommentarzieranbieter ausgelöst wird, wenn Kommentare hinzugefügt oder entfernt werden.

  1. Fügen Sie dem CommentAdornmentTest-Projekt eine Klassendatei hinzu, und nennen Sie sie CommentAdornmentManager.

  2. Fügen Sie die folgenden using Direktiven hinzu.

    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. Fügen Sie eine Klasse namens CommentAdornmentManagerhinzu.

    internal class CommentAdornmentManager
        {
        }
    
  4. Fügen Sie einige private Felder hinzu.

    private readonly IWpfTextView view;
    private readonly IAdornmentLayer layer;
    private readonly CommentAdornmentProvider provider;
    
  5. Fügen Sie einen Konstruktor hinzu, der den Manager für die LayoutChanged Ereignisse und Closed ereignisse sowie für das CommentsChanged Ereignis abonniert. Der Konstruktor ist privat, da der Manager von der statischen Create() Methode instanziiert wird.

    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. Fügen Sie die Create() Methode hinzu, die einen Anbieter abruft oder bei Bedarf eins erstellt.

    public static CommentAdornmentManager Create(IWpfTextView view)
    {
        return view.Properties.GetOrCreateSingletonProperty<CommentAdornmentManager>(delegate { return new CommentAdornmentManager(view); });
    }
    
  7. Fügen Sie den CommentsChanged Handler hinzu.

    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. Fügen Sie den Closed Handler hinzu.

    private void OnClosed(object sender, EventArgs e)
    {
        this.provider.Detach();
        this.view.LayoutChanged -= OnLayoutChanged;
        this.view.Closed -= OnClosed;
    }
    
  9. Fügen Sie den LayoutChanged Handler hinzu.

    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. Fügen Sie die private Methode hinzu, die den Kommentar zeichnet.

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

Verwenden des Menübefehls zum Hinzufügen des Kommentars

Sie können den Menübefehl verwenden, um ein Kommentarzieren zu erstellen, indem Sie die MenuItemCallback Methode des VSPackage implementieren.

  1. Fügen Sie dem MenuCommandTest-Projekt die folgenden Verweise hinzu:

    • Microsoft.VisualStudio.TextManager.Interop

    • Microsoft.VisualStudio.Editor

    • Microsoft.VisualStudio.Text.UI.Wpf

  2. Öffnen Sie die Datei "AddAdornment.cs ", und fügen Sie die folgenden using Direktiven hinzu.

    using Microsoft.VisualStudio.TextManager.Interop;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Editor;
    using CommentAdornmentTest;
    
  3. Löschen Sie die Execute() Methode, und fügen Sie den folgenden Befehlshandler hinzu.

    private async void AddAdornmentHandler(object sender, EventArgs e)
    {
    }
    
  4. Fügen Sie Code hinzu, um die aktive Ansicht abzurufen. Sie müssen die SVsTextManager Visual Studio-Shell abrufen, um die aktive IVsTextView.

    private async void AddAdornmentHandler(object sender, EventArgs e)
    {
        IVsTextManager txtMgr = (IVsTextManager) await ServiceProvider.GetServiceAsync(typeof(SVsTextManager));
        IVsTextView vTextView = null;
        int mustHaveFocus = 1;
        txtMgr.GetActiveView(mustHaveFocus, null, out vTextView);
    }
    
  5. Wenn es sich bei dieser Textansicht um eine Instanz einer Editortextansicht handelt, können Sie sie in die IVsUserData Schnittstelle umwandeln und dann die IWpfTextViewHost zugeordneten Elemente IWpfTextViewabrufen. Verwenden Sie die IWpfTextViewHost Methode, um die Connector.Execute() Methode aufzurufen, die den Kommentar-Zieranbieter abruft und die Dekoration hinzufügt. Der Befehlshandler sollte nun wie dieser Code aussehen:

    private async void AddAdornmentHandler(object sender, EventArgs e)
    {
        IVsTextManager txtMgr = (IVsTextManager) await ServiceProvider.GetServiceAsync(typeof(SVsTextManager));
        IVsTextView vTextView = null;
        int mustHaveFocus = 1;
        txtMgr.GetActiveView(mustHaveFocus, null, out vTextView);
        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;
        Connector.Execute(viewHost);
    }
    
  6. Legen Sie die AddAdornmentHandler-Methode als Handler für den AddAdornment-Befehl im AddAdornment-Konstruktor fest.

    private AddAdornment(AsyncPackage package, OleMenuCommandService commandService)
    {
        this.package = package ?? throw new ArgumentNullException(nameof(package));
        commandService = commandService ?? throw new ArgumentNullException(nameof(commandService));
    
        var menuCommandID = new CommandID(CommandSet, CommandId);
        var menuItem = new MenuCommand(this.AddAdornmentHandler, menuCommandID);
        commandService.AddCommand(menuItem);
    }
    

Erstellen und Testen des Codes

  1. Erstellen Sie die Projektmappe, und beginnen Sie mit dem Debuggen. Die experimentelle Instanz sollte angezeigt werden.

  2. Erstellen einer Textdatei Geben Sie Text ein, und wählen Sie ihn aus.

  3. Klicken Sie im Menü "Extras " auf "Schmücken hinzufügen". Eine Sprechblase sollte auf der rechten Seite des Textfensters angezeigt werden und sollte Text enthalten, der dem folgenden Text ähnelt.

    IhrUserName

    Fourscore...