Exemplarische Vorgehensweise: Vorschläge zur Anzeige von Glühbirne
Glühbirnen sind Symbole im Visual Studio-Editor, die erweitert werden, um eine Reihe von Aktionen anzuzeigen, z. B. Korrekturen für Probleme, die von den integrierten Codeanalysatoren oder der Codeumgestaltung identifiziert werden.
In den Editoren für Visual C# und Visual Basic können Sie auch die .NET-Compilerplattform ("Roslyn") verwenden, um Eigene Codeanalysatoren mit Aktionen zu schreiben und zu verpacken, die Glühbirnen automatisch anzeigen. Weitere Informationen finden Sie unter:
Gewusst wie: Schreiben einer Visual Basic-Diagnose- und Codekorrektur
Andere Sprachen wie C++ bieten auch Glühbirnen für einige schnelle Aktionen, z. B. einen Vorschlag zum Erstellen einer Stubimplementierung dieser Funktion.
So sieht eine Glühbirne aus. In einem Visual Basic- oder Visual C#-Projekt wird unter einem Variablennamen ein roter Wellenschalter angezeigt, wenn er ungültig ist. Wenn Sie mit dem Mauszeiger auf den ungültigen Bezeichner zeigen, wird in der Nähe des Cursors eine Glühbirne angezeigt.
Wenn Sie auf den Abwärtspfeil durch die Glühbirne klicken, wird eine Reihe von vorgeschlagenen Aktionen zusammen mit einer Vorschau der ausgewählten Aktion angezeigt. In diesem Fall werden die Änderungen angezeigt, die an Ihrem Code vorgenommen werden, wenn Sie die Aktion ausführen.
Sie können Glühbirnen verwenden, um Ihre eigenen vorgeschlagenen Aktionen bereitzustellen. Sie können z. B. Aktionen bereitstellen, um geschweifte geschweifte Klammern in eine neue Zeile zu verschieben oder sie an das Ende der vorherigen Zeile zu verschieben. Die folgende exemplarische Vorgehensweise zeigt, wie Sie eine Glühbirne erstellen, die auf dem aktuellen Wort angezeigt wird und zwei vorgeschlagene Aktionen enthält: In Großbuchstaben konvertieren und in Kleinbuchstaben konvertieren.
Erstellen eines Projekts für verwaltetes Erweiterbarkeitsframework (MEF)
Erstellen Sie ein C#VSIX-Projekt. (Im Dialogfeld "Neues Projekt ", wählen Sie Visual C# / Erweiterbarkeit und dann VSIX-Projekt aus.) Benennen Sie die Lösung
LightBulbTest
.Fügen Sie dem Projekt eine Elementvorlage für Editorklassifizierer hinzu. Weitere Informationen finden Sie unter Erstellen einer Erweiterung mit einer Editorelementvorlage.
Löschen Sie die vorhandenen Klassendateien.
Fügen Sie den folgenden Verweis auf das Projekt hinzu, und legen Sie "Lokal kopieren" auf folgendes fest
False
:Microsoft.VisualStudio.Language.IntelliSense
Fügen Sie eine neue Klassendatei hinzu, und nennen Sie sie LightBulbTest.
Fügen Sie die folgenden using-Direktiven hinzu:
using System; using System.Linq; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities; using System.ComponentModel.Composition; using System.Threading;
Implementieren des Anbieters der Glühbirne
Löschen Sie in der Klassendatei LightBulbTest.cs die LightBulbTest-Klasse. Fügen Sie eine Klasse namens TestSuggestedActionsSourceProvider hinzu, die implementiert ISuggestedActionsSourceProviderwird. Exportieren Sie ihn mit dem Namen " Vorgeschlagene Testaktionen " und einem ContentTypeAttribute "Text".
[Export(typeof(ISuggestedActionsSourceProvider))] [Name("Test Suggested Actions")] [ContentType("text")] internal class TestSuggestedActionsSourceProvider : ISuggestedActionsSourceProvider
Importieren Sie die ITextStructureNavigatorSelectorService Klasse innerhalb der Quellanbieterklasse, und fügen Sie sie als Eigenschaft hinzu.
[Import(typeof(ITextStructureNavigatorSelectorService))] internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
Implementieren Sie die CreateSuggestedActionsSource Methode, um ein ISuggestedActionsSource Objekt zurückzugeben. Die Quelle wird im nächsten Abschnitt erläutert.
public ISuggestedActionsSource CreateSuggestedActionsSource(ITextView textView, ITextBuffer textBuffer) { if (textBuffer == null || textView == null) { return null; } return new TestSuggestedActionsSource(this, textView, textBuffer); }
Implementieren der ISuggestedActionSource
Die vorgeschlagene Aktionsquelle ist für das Sammeln der vorgeschlagenen Aktionen und das Hinzufügen im richtigen Kontext verantwortlich. In diesem Fall ist der Kontext das aktuelle Wort, und die vorgeschlagenen Aktionen sind "UpperCaseSuggestedAction " und "LowerCaseSuggestedAction", die im folgenden Abschnitt erläutert wird.
Fügen Sie eine Klasse TestSuggestedActionsSource hinzu, die implementiert ISuggestedActionsSourcewird.
internal class TestSuggestedActionsSource : ISuggestedActionsSource
Fügen Sie private, schreibgeschützte Felder für den vorgeschlagenen Aktionsquellenanbieter, den Textpuffer und die Textansicht hinzu.
private readonly TestSuggestedActionsSourceProvider m_factory; private readonly ITextBuffer m_textBuffer; private readonly ITextView m_textView;
Fügen Sie einen Konstruktor hinzu, der die privaten Felder festlegt.
public TestSuggestedActionsSource(TestSuggestedActionsSourceProvider testSuggestedActionsSourceProvider, ITextView textView, ITextBuffer textBuffer) { m_factory = testSuggestedActionsSourceProvider; m_textBuffer = textBuffer; m_textView = textView; }
Fügen Sie eine private Methode hinzu, die das Wort zurückgibt, das sich derzeit unter dem Cursor befindet. Die folgende Methode untersucht die aktuelle Position des Cursors und fragt den Textstrukturnavigator nach dem Umfang des Worts. Wenn sich der Cursor auf einem Wort befindet, wird der TextExtent Wert im Ausgabeparameter zurückgegeben. Andernfalls wird
null
derout
Parameter und die Methode zurückgegebenfalse
.private bool TryGetWordUnderCaret(out TextExtent wordExtent) { ITextCaret caret = m_textView.Caret; SnapshotPoint point; if (caret.Position.BufferPosition > 0) { point = caret.Position.BufferPosition - 1; } else { wordExtent = default(TextExtent); return false; } ITextStructureNavigator navigator = m_factory.NavigatorService.GetTextStructureNavigator(m_textBuffer); wordExtent = navigator.GetExtentOfWord(point); return true; }
Implementieren Sie die HasSuggestedActionsAsync-Methode. Der Editor ruft diese Methode auf, um herauszufinden, ob die Glühbirne angezeigt werden soll. Dieser Aufruf wird häufig ausgeführt, wenn der Cursor von einer Zeile zu einer anderen wechselt, oder wenn die Maus über eine Fehler-Wellenlinie bewegt wird. Es ist asynchron, um anderen UI-Vorgängen zu ermöglichen, während diese Methode funktioniert. In den meisten Fällen muss diese Methode einige Analyse und Analyse der aktuellen Zeile durchführen, sodass die Verarbeitung einige Zeit in Anspruch nehmen kann.
In dieser Implementierung ruft sie asynchron ab TextExtent und bestimmt, ob der Umfang erheblich ist, wie in, ob er einen anderen Text als Leerzeichen hat.
public Task<bool> HasSuggestedActionsAsync(ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, CancellationToken cancellationToken) { return Task.Factory.StartNew(() => { TextExtent extent; if (TryGetWordUnderCaret(out extent)) { // don't display the action if the extent has whitespace return extent.IsSignificant; } return false; }); }
Implementieren Sie die GetSuggestedActions Methode, die ein Array von SuggestedActionSet Objekten zurückgibt, die die verschiedenen ISuggestedAction Objekte enthalten. Diese Methode wird aufgerufen, wenn die Glühbirne erweitert wird.
Warnung
Sie sollten sicherstellen, dass die Implementierungen von
HasSuggestedActionsAsync()
undGetSuggestedActions()
konsistent sind, d. h., wennHasSuggestedActionsAsync()
sie zurückgegebentrue
werden, einigeGetSuggestedActions()
Aktionen anzeigen sollen. In vielen FällenHasSuggestedActionsAsync()
wird kurz davorGetSuggestedActions()
aufgerufen, aber dies ist nicht immer der Fall. Wenn der Benutzer z. B. die Glühbirnenaktionen aufruft, wird nurGetSuggestedActions()
strg+.) aufgerufen.public IEnumerable<SuggestedActionSet> GetSuggestedActions(ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, CancellationToken cancellationToken) { TextExtent extent; if (TryGetWordUnderCaret(out extent) && extent.IsSignificant) { ITrackingSpan trackingSpan = range.Snapshot.CreateTrackingSpan(extent.Span, SpanTrackingMode.EdgeInclusive); var upperAction = new UpperCaseSuggestedAction(trackingSpan); var lowerAction = new LowerCaseSuggestedAction(trackingSpan); return new SuggestedActionSet[] { new SuggestedActionSet(new ISuggestedAction[] { upperAction, lowerAction }) }; } return Enumerable.Empty<SuggestedActionSet>(); }
Definieren sie ein
SuggestedActionsChanged
Ereignis.public event EventHandler<EventArgs> SuggestedActionsChanged;
Um die Implementierung abzuschließen, fügen Sie Implementierungen für die
Dispose()
undTryGetTelemetryId()
Methoden hinzu. Sie möchten keine Telemetrie ausführen. Geben Sie also einfach die GUID zurückfalse
und legen Sie sie aufEmpty
fest.public void Dispose() { } public bool TryGetTelemetryId(out Guid telemetryId) { // This is a sample provider and doesn't participate in LightBulb telemetry telemetryId = Guid.Empty; return false; }
Implementieren von Glühbirnenaktionen
Fügen Sie im Projekt einen Verweis auf Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.dll hinzu, und legen Sie "Lokal kopieren" auf
False
" fest.Erstellen Sie zwei Klassen, die erste mit dem Namen
UpperCaseSuggestedAction
und die zweite mit dem NamenLowerCaseSuggestedAction
. Beide Klassen implementieren ISuggestedAction.internal class UpperCaseSuggestedAction : ISuggestedAction internal class LowerCaseSuggestedAction : ISuggestedAction
Beide Klassen sind bis auf eine Ausnahme identisch: Die eine ruft ToUpper und die andere ToLower auf. In den folgenden Schritten wird nur die Klasse für die Umwandlung in Großbuchstaben behandelt; Sie müssen aber beide Klassen implementieren. Verwenden Sie diese Schritte als Muster für die Implementierung der Aktion zur Umwandlung in Kleinbuchstaben.
Fügen Sie die folgenden Using-Direktiven für diese Klassen hinzu:
using Microsoft.VisualStudio.Imaging.Interop; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media;
Deklarieren Sie einen Satz privater Felder.
private ITrackingSpan m_span; private string m_upper; private string m_display; private ITextSnapshot m_snapshot;
Fügen Sie einen Konstruktor hinzu, der die Felder festlegt.
public UpperCaseSuggestedAction(ITrackingSpan span) { m_span = span; m_snapshot = span.TextBuffer.CurrentSnapshot; m_upper = span.GetText(m_snapshot).ToUpper(); m_display = string.Format("Convert '{0}' to upper case", span.GetText(m_snapshot)); }
Implementieren Sie die GetPreviewAsync Methode so, dass sie die Aktionsvorschau anzeigt.
public Task<object> GetPreviewAsync(CancellationToken cancellationToken) { var textBlock = new TextBlock(); textBlock.Padding = new Thickness(5); textBlock.Inlines.Add(new Run() { Text = m_upper }); return Task.FromResult<object>(textBlock); }
Implementieren Sie die GetActionSetsAsync Methode so, dass sie eine leere SuggestedActionSet Aufzählung zurückgibt.
public Task<IEnumerable<SuggestedActionSet>> GetActionSetsAsync(CancellationToken cancellationToken) { return Task.FromResult<IEnumerable<SuggestedActionSet>>(null); }
Implementieren Sie die Eigenschaften wie folgt:
public bool HasActionSets { get { return false; } } public string DisplayText { get { return m_display; } } public ImageMoniker IconMoniker { get { return default(ImageMoniker); } } public string IconAutomationText { get { return null; } } public string InputGestureText { get { return null; } } public bool HasPreview { get { return true; } }
Implementieren Sie die Invoke-Methode, indem Sie den Text im Bereich durch entsprechende Großbuchstaben ersetzen.
public void Invoke(CancellationToken cancellationToken) { m_span.TextBuffer.Replace(m_span.GetSpan(m_snapshot), m_upper); }
Warnung
Die Glühbirnenaktion Invoke-Methode wird nicht erwartet, dass die Benutzeroberfläche angezeigt wird. Wenn ihre Aktion neue UI (z. B. ein Vorschau- oder Auswahldialogfeld) anzeigt, zeigen Sie die Benutzeroberfläche nicht direkt in der Invoke-Methode an, sondern planen Sie stattdessen, die Benutzeroberfläche nach der Rückgabe von Invoke anzuzeigen.
Um die Implementierung abzuschließen, fügen Sie die
Dispose()
UndTryGetTelemetryId()
Methoden hinzu.public void Dispose() { } public bool TryGetTelemetryId(out Guid telemetryId) { // This is a sample action and doesn't participate in LightBulb telemetry telemetryId = Guid.Empty; return false; }
Vergessen Sie nicht, dasselbe zu tun, um
LowerCaseSuggestedAction
den Anzeigetext in "Konvertieren "{0} in Kleinbuchstabe" und den Aufruf ToUpper zu ToLowerändern.
Erstellen und Testen des Codes
Um diesen Code zu testen, erstellen Sie die LightBulbTest-Lösung, und führen Sie sie in der Experimental-Instanz aus.
Erstellen Sie die Projektmappe.
Wenn Sie dieses Projekt im Debugger ausführen, wird eine zweite Instanz von Visual Studio gestartet.
Erstellen Sie eine Textdatei, und geben Sie Text ein. Sie sollten links neben dem Text eine Glühbirne sehen.
Zeigen Sie auf die Glühbirne. Es sollte ein Pfeil nach unten angezeigt werden.
Wenn Sie auf die Glühbirne klicken, sollten zwei vorgeschlagene Aktionen zusammen mit der Vorschau der ausgewählten Aktion angezeigt werden.
Wenn Sie auf die erste Aktion klicken, sollte der gesamte Text im aktuellen Wort in Großbuchstaben konvertiert werden. Wenn Sie auf die zweite Aktion klicken, sollte der gesamte Text in Kleinbuchstaben konvertiert werden.