Przewodnik: używanie polecenia powłoki z rozszerzeniem edytora
W programie VSPackage można dodawać do edytora funkcje, takie jak polecenia menu. W tym przewodniku pokazano, jak dodać ozdobę do widoku tekstowego w edytorze, wywołując polecenie menu.
W tym przewodniku przedstawiono użycie pakietu VSPackage wraz z częścią składnika Managed Extensibility Framework (MEF). Aby zarejestrować polecenie menu w powłoce programu Visual Studio, musisz użyć pakietu VSPackage. Możesz też użyć polecenia , aby uzyskać dostęp do części składnika MEF.
Tworzenie rozszerzenia za pomocą polecenia menu
Utwórz pakiet VSPackage, który umieszcza polecenie menu o nazwie Dodaj ozdobę w menu Narzędzia .
Utwórz projekt VSIX języka C# o nazwie
MenuCommandTest
i dodaj niestandardową nazwę szablonu elementu polecenia AddAdornment. Aby uzyskać więcej informacji, zobacz Create an extension with a menu command (Tworzenie rozszerzenia za pomocą polecenia menu).Zostanie otwarte rozwiązanie o nazwie MenuCommandTest. Plik MenuCommandTestPackage zawiera kod, który tworzy polecenie menu i umieszcza go w menu Narzędzia . W tym momencie polecenie powoduje wyświetlenie pola komunikatu. W kolejnych krokach pokazano, jak zmienić tę zmianę, aby wyświetlić ozdobę komentarza.
Otwórz plik source.extension.vsixmanifest w edytorze manifestu VSIX. Karta
Assets
powinna zawierać wiersz dla pakietu Microsoft.VisualStudio.VsPackage o nazwie MenuCommandTest.Zapisz i zamknij plik source.extension.vsixmanifest .
Dodawanie rozszerzenia MEF do rozszerzenia polecenia
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy węzeł rozwiązania, kliknij polecenie Dodaj, a następnie kliknij polecenie Nowy projekt. W oknie dialogowym Dodawanie nowego projektu kliknij pozycję Rozszerzalność w obszarze Visual C#, a następnie pozycję Projekt VSIX. Nadaj projektowi
CommentAdornmentTest
nazwę .Ponieważ ten projekt będzie współdziałać z zestawem VSPackage o silnej nazwie, należy podpisać zestaw. Możesz ponownie użyć pliku klucza utworzonego już dla zestawu VSPackage.
Otwórz właściwości projektu i wybierz kartę Podpisywanie .
Wybierz pozycję Podpisz zestaw.
W obszarze Wybierz plik klucza silnej nazwy wybierz plik Key.snk wygenerowany dla zestawu MenuCommandTest.
Zapoznaj się z rozszerzeniem MEF w projekcie VSPackage
Ponieważ dodasz składnik MEF do pakietu VSPackage, musisz określić oba rodzaje zasobów w manifeście.
Uwaga
Aby uzyskać więcej informacji na temat mef, zobacz Managed Extensibility Framework (MEF).
Aby odwołać się do składnika MEF w projekcie VSPackage
W projekcie MenuCommandTest otwórz plik source.extension.vsixmanifest w edytorze manifestu VSIX.
Na karcie Zasoby kliknij pozycję Nowy.
Na liście Typ wybierz pozycję Microsoft.VisualStudio.MefComponent.
Na liście Źródło wybierz pozycję Projekt w bieżącym rozwiązaniu.
Na liście Projekt wybierz pozycję KomentarzAdornmentTest.
Zapisz i zamknij plik source.extension.vsixmanifest .
Upewnij się, że projekt MenuCommandTest ma odwołanie do projektu CommentAdornmentTest.
W projekcie CommentAdornmentTest ustaw projekt na tworzenie zestawu. W Eksplorator rozwiązań wybierz projekt i poszukaj w oknie Właściwości właściwości właściwości dla właściwości Copy Build Output to OutputDirectory (Kopiuj dane wyjściowe kompilacji do właściwości OutputDirectory) i ustaw ją na true.
Definiowanie adornmentu komentarza
Sama ozdoba komentarza składa się z elementu ITrackingSpan , który śledzi zaznaczony tekst, a niektóre ciągi reprezentujące autora i opis tekstu.
Aby zdefiniować ozdobę komentarza
W projekcie CommentAdornmentTest dodaj nowy plik klasy i nadaj mu
CommentAdornment
nazwę .Dodaj następujące odwołania:
Microsoft.VisualStudio.CoreUtility
Microsoft.VisualStudio.Text.Data
Microsoft.VisualStudio.Text.Logic
Microsoft.VisualStudio.Text.UI
Microsoft.VisualStudio.Text.UI.Wpf
System.componentmodel.composition
Rdzeń prezentacji
Element PresentationFramework
Windowsbase
Dodaj następującą
using
dyrektywę.using Microsoft.VisualStudio.Text;
Plik powinien zawierać klasę o nazwie
CommentAdornment
.internal class CommentAdornment
Dodaj trzy pola do
CommentAdornment
klasy , ITrackingSpanautora i opisu.public readonly ITrackingSpan Span; public readonly string Author; public readonly string Text;
Dodaj konstruktor, który inicjuje pola.
public CommentAdornment(SnapshotSpan span, string author, string text) { this.Span = span.Snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeExclusive); this.Author = author; this.Text = text; }
Tworzenie elementu wizualizacji dla elementu ozdobnego
Zdefiniuj element wizualny dla elementu ozdobnego. W tym przewodniku zdefiniuj kontrolkę dziedziczą z klasy CanvasWindows Presentation Foundation (WPF).
Utwórz klasę w projekcie CommentAdornmentTest i nadaj mu
CommentBlock
nazwę .Dodaj następujące
using
dyrektywy.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;
Ustaw klasę na dziedziczenie
CommentBlock
z klasy Canvas.internal class CommentBlock : Canvas { }
Dodaj niektóre pola prywatne, aby zdefiniować wizualne aspekty ozdoby.
private Geometry textGeometry; private Grid commentGrid; private static Brush brush; private static Pen solidPen; private static Pen dashPen;
Dodaj konstruktor, który definiuje ozdobę komentarza i dodaje odpowiedni tekst.
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); }
Zaimplementuj również procedurę obsługi zdarzeń OnRender , która rysuje ozdobę.
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); } }
Dodawanie elementu IWpfTextViewCreationListener
Element IWpfTextViewCreationListener jest częścią składnika MEF, której można użyć do nasłuchiwania zdarzeń tworzenia.
Dodaj plik klasy do projektu CommentAdornmentTest i nadaj mu
Connector
nazwę .Dodaj następujące
using
dyrektywy.using System.ComponentModel.Composition; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Utilities;
Zadeklaruj klasę, która implementuje IWpfTextViewCreationListenerelement , i wyeksportuj ją za pomocą ContentTypeAttribute wartości "text" i klasy TextViewRoleAttribute Document. Atrybut typu zawartości określa rodzaj zawartości, do której ma zastosowanie składnik. Typ tekstowy jest typem podstawowym dla wszystkich typów plików innych niż binarne. W związku z tym prawie każdy utworzony widok tekstowy będzie tego typu. Atrybut roli widoku tekstu określa rodzaj widoku tekstu, do którego ma zastosowanie składnik. Role widoku tekstu dokumentu zwykle pokazują tekst składający się z wierszy i jest przechowywany w pliku.
Zaimplementuj metodę TextViewCreated tak, aby wywołała zdarzenie statyczne
Create()
klasyCommentAdornmentManager
.public void TextViewCreated(IWpfTextView textView) { CommentAdornmentManager.Create(textView); }
Dodaj metodę, której można użyć do wykonania polecenia.
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); } }
Definiowanie warstwy ozdobności
Aby dodać nową ozdobę, należy zdefiniować warstwę ozdobną.
Aby zdefiniować warstwę ozdobną
Connector
W klasie zadeklaruj pole publiczne typu AdornmentLayerDefinitioni wyeksportuj je za NameAttribute pomocą elementu , który określa unikatową nazwę warstwy ozdobnej oraz właściwość OrderAttribute , która definiuje relację Z tej warstwy ozdobnej z innymi warstwami widoku tekstu (tekst, daszek i zaznaczenie).[Export(typeof(AdornmentLayerDefinition))] [Name("CommentAdornmentLayer")] [Order(After = PredefinedAdornmentLayers.Selection, Before = PredefinedAdornmentLayers.Text)] public AdornmentLayerDefinition commentLayerDefinition;
Podaj ozdoby komentarzy
Podczas definiowania adornmentu zaimplementuj również dostawcę dodawania komentarzy i menedżera dodawania komentarzy. Dostawca dodawania komentarzy przechowuje listę ozdobników komentarzy, nasłuchuje Changed zdarzeń w bazowym buforze tekstu i usuwa ozdobniki komentarzy po usunięciu tekstu bazowego.
Dodaj nowy plik klasy do projektu CommentAdornmentTest i nadaj mu
CommentAdornmentProvider
nazwę .Dodaj następujące
using
dyrektywy.using System; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor;
Dodaj klasę o nazwie
CommentAdornmentProvider
.internal class CommentAdornmentProvider { }
Dodaj pola prywatne dla buforu tekstowego i listę dodatków komentarzy powiązanych z buforem.
private ITextBuffer buffer; private IList<CommentAdornment> comments = new List<CommentAdornment>();
Dodaj konstruktor dla elementu
CommentAdornmentProvider
. Ten konstruktor powinien mieć dostęp prywatny, ponieważ dostawca jest tworzone przez metodęCreate()
. Konstruktor dodaje proceduręOnBufferChanged
obsługi zdarzeń do Changed zdarzenia.private CommentAdornmentProvider(ITextBuffer buffer) { this.buffer = buffer; //listen to the Changed event so we can react to deletions. this.buffer.Changed += OnBufferChanged; }
Dodaj metodę
Create()
.public static CommentAdornmentProvider Create(IWpfTextView view) { return view.Properties.GetOrCreateSingletonProperty<CommentAdornmentProvider>(delegate { return new CommentAdornmentProvider(view.TextBuffer); }); }
Dodaj metodę
Detach()
.public void Detach() { if (this.buffer != null) { //remove the Changed listener this.buffer.Changed -= OnBufferChanged; this.buffer = null; } }
Dodaj procedurę obsługi zdarzeń
OnBufferChanged
.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; }
Dodaj deklarację dla
CommentsChanged
zdarzenia.public event EventHandler<CommentsChangedEventArgs> CommentsChanged;
Utwórz metodę
Add()
, aby dodać ozdobę.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)); }
Dodaj metodę
RemoveComments()
.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; }
Dodaj metodę zwracającą
GetComments()
wszystkie komentarze w danym zakresie migawek.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); }
Dodaj klasę o nazwie
CommentsChangedEventArgs
, w następujący sposób.internal class CommentsChangedEventArgs : EventArgs { public readonly CommentAdornment CommentAdded; public readonly CommentAdornment CommentRemoved; public CommentsChangedEventArgs(CommentAdornment added, CommentAdornment removed) { this.CommentAdded = added; this.CommentRemoved = removed; } }
Zarządzanie ozdobami komentarzy
Menedżer dodawania komentarzy tworzy ozdobę i dodaje ją do warstwy ozdobności. Nasłuchuje LayoutChanged zdarzeń i Closed , aby można było przenosić lub usuwać ozdoby. Nasłuchuje CommentsChanged
również zdarzenia, które jest wyzwalane przez dostawcę dodawania lub usuwania komentarzy.
Dodaj plik klasy do projektu CommentAdornmentTest i nadaj mu
CommentAdornmentManager
nazwę .Dodaj następujące
using
dyrektywy.using System; using System.Collections.Generic; using System.Windows.Media; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Formatting;
Dodaj klasę o nazwie
CommentAdornmentManager
.internal class CommentAdornmentManager { }
Dodaj niektóre pola prywatne.
private readonly IWpfTextView view; private readonly IAdornmentLayer layer; private readonly CommentAdornmentProvider provider;
Dodaj konstruktor, który subskrybuje menedżera do zdarzeń LayoutChanged i Closed , a także do
CommentsChanged
zdarzenia. Konstruktor jest prywatny, ponieważ menedżer jest tworzone przez metodę statycznąCreate()
.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; }
Dodaj metodę
Create()
, która pobiera dostawcę lub tworzy go w razie potrzeby.public static CommentAdornmentManager Create(IWpfTextView view) { return view.Properties.GetOrCreateSingletonProperty<CommentAdornmentManager>(delegate { return new CommentAdornmentManager(view); }); }
Dodaj procedurę
CommentsChanged
obsługi.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); }
Dodaj procedurę Closed obsługi.
private void OnClosed(object sender, EventArgs e) { this.provider.Detach(); this.view.LayoutChanged -= OnLayoutChanged; this.view.Closed -= OnClosed; }
Dodaj procedurę LayoutChanged obsługi.
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); } } }
Dodaj metodę prywatną, która rysuje komentarz.
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); } }
Użyj polecenia menu, aby dodać ozdobę komentarza
Za pomocą polecenia menu można utworzyć ozdobę komentarza, implementując MenuItemCallback
metodę pakietu VSPackage.
Dodaj następujące odwołania do projektu MenuCommandTest:
Microsoft.VisualStudio.TextManager.Interop
Microsoft.VisualStudio.Editor
Microsoft.VisualStudio.Text.UI.Wpf
Otwórz plik AddAdornment.cs i dodaj następujące
using
dyrektywy.using Microsoft.VisualStudio.TextManager.Interop; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Editor; using CommentAdornmentTest;
Usuń metodę i dodaj następującą procedurę
Execute()
obsługi poleceń.private async void AddAdornmentHandler(object sender, EventArgs e) { }
Dodaj kod, aby uzyskać aktywny widok. Aby uzyskać aktywny
IVsTextView
element, musisz pobraćSVsTextManager
powłokę programu Visual Studio.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); }
Jeśli ten widok tekstu jest wystąpieniem widoku tekstu edytora, możesz rzutować go do interfejsu IVsUserData , a następnie pobrać IWpfTextViewHost element i skojarzony z nim IWpfTextViewelement . IWpfTextViewHost Użyj metody , aby wywołać metodę , która pobiera dostawcę
Connector.Execute()
dodawania komentarzy i dodaje ozdobę. Procedura obsługi poleceń powinna teraz wyglądać następująco: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); }
Ustaw metodę AddAdornmentHandler jako procedurę obsługi dla polecenia AddAdornment w konstruktorze AddAdornment.
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); }
Kompilowanie i testowanie kodu
Skompiluj rozwiązanie i rozpocznij debugowanie. Powinno zostać wyświetlone wystąpienie eksperymentalne.
Utwórz plik tekstowy. Wpisz jakiś tekst, a następnie wybierz go.
W menu Narzędzia kliknij pozycję Wywołaj dodaj ozdobę. Dymek powinien być wyświetlany po prawej stronie okna tekstowego i powinien zawierać tekst podobny do poniższego.
Nazwa użytkownika
Fourscore...