Creare un'estensione semplice

In Creare la prima estensione si è appreso come usare il modello di progetto VisualStudio.Extensibility per creare un progetto di estensione e come compilarlo ed eseguirne il debug nell'istanza sperimentale di Visual Studio.

In questa esercitazione si apprenderà come creare un'estensione con un semplice comando che esegue operazioni nell'editor di Visual Studio. In questo caso, inserisce un GUID appena generato. Si vedrà anche come indicare a Visual Studio i tipi di file per cui è abilitata l'estensione GUID e come visualizzare il nuovo comando come barra degli strumenti o voce di menu.

L'esempio completo per questa esercitazione è disponibile qui.

L'esercitazione contiene i passaggi seguenti:

Configurare il comando

In questo passaggio verranno fornite informazioni sulle opzioni per la configurazione e l'inserimento del comando. Lo scopo dell'hosting del comando consiste nell'esporlo all'utente in qualche modo, ad esempio l'aggiunta di una voce di menu o un pulsante della barra dei comandi.

Il modello di progetto o l'esempio creato nell'esercitazione Creare la prima estensione è costituito da un singolo file C# che include già una Command classe. È possibile aggiornare questa funzionalità sul posto.

  1. Rinominare il Command1.cs file in InsertGuidCommand.cs, rinominare la classe InsertGuidCommand, aggiornare la CommandConfiguration proprietà .

    public override CommandConfiguration CommandConfiguration => new("%InsertGuidCommand.DisplayName%")
    {
        Placements = new[] { CommandPlacement.KnownPlacements.ExtensionsMenu },
    };
    

    Placements specifica dove deve essere visualizzato il comando nell'IDE. In questo caso, il comando viene inserito nel menu Estensioni, uno dei menu di primo livello in Visual Studio.

    L'argomento del CommandConfiguration costruttore è il nome visualizzato del comando, ovvero il testo del menu. Il nome visualizzato è racchiuso tra % caratteri perché fa riferimento a una risorsa stringa da .vsextension/string-resources.json per supportare la localizzazione.

  2. Aggiornare .vsextension/string-resources.json con il nome visualizzato di InsertGuidCommand.

    {
      "InsertGuidCommand.DisplayName": "Insert new guid"
    }
    
  3. Aggiungere la proprietà Icon.

    public override CommandConfiguration CommandConfiguration => new("%InsertGuidCommand.DisplayName%")
    {
        Placements = new[] { CommandPlacement.KnownPlacements.ExtensionsMenu },
        Icon = new(ImageMoniker.KnownValues.OfficeWebExtension, IconSettings.IconAndText),
    };
    

    È possibile specificare un'icona predefinita nota, in questo caso OfficeWebExtensiono caricare immagini per l'icona come descritto in Aggiungere comandi di Visual Studio. Il secondo argomento è un'enumerazione che determina la modalità di visualizzazione del comando nelle barre degli strumenti (oltre alla relativa posizione in un menu). L'opzione IconSettings.IconAndText indica che mostra l'icona e il nome visualizzato l'uno accanto all'altro.

  4. Aggiungere la VisibleWhen proprietà , che specifica le condizioni che devono essere applicate per l'elemento da visualizzare all'utente.

    public override CommandConfiguration CommandConfiguration => new("%InsertGuidCommand.DisplayName%")
    {
        Placements = new[] { CommandPlacement.KnownPlacements.ExtensionsMenu },
        Icon = new(ImageMoniker.KnownValues.OfficeWebExtension, IconSettings.IconAndText),
        VisibleWhen = ActivationConstraint.ClientContext(ClientContextKey.Shell.ActiveEditorContentType, ".+"),
    };
    

Per altre informazioni, vedere Uso dei vincoli di attivazione basati su regole.

Creare il metodo di esecuzione

In questo passaggio si implementa il metodo del ExecuteCommandAsync comando, che definisce cosa accade quando l'utente sceglie la voce di menu o preme l'elemento nella barra degli strumenti per il comando.

Copiare il codice seguente per implementare il metodo .

public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
    {
        Requires.NotNull(context, nameof(context));
        var newGuidString = Guid.NewGuid().ToString("N", CultureInfo.CurrentCulture);

        using var textView = await context.GetActiveTextViewAsync(cancellationToken);
        if (textView is null)
        {
            this.logger.TraceInformation("There was no active text view when command is executed.");
            return;
        }

        await this.Extensibility.Editor().EditAsync(
            batch =>
            {
                textView.Document.AsEditable(batch).Replace(textView.Selection.Extent, newGuidString);
            },
            cancellationToken);
    }

La prima riga convalida gli argomenti, quindi viene creato un nuovo Guid oggetto da usare in un secondo momento.

Viene quindi creato un ITextViewSnapshot oggetto (l'oggetto textView qui) chiamando il metodo GetActiveTextViewAsyncasincrono . Un token di annullamento viene passato per mantenere la possibilità di annullare la richiesta asincrona, ma questa parte non viene illustrata in questo esempio. Se non si ottiene correttamente una visualizzazione di testo, si scrive nel log e si termina senza eseguire altre operazioni.

A questo momento è possibile chiamare il metodo asincrono che invia una richiesta di modifica all'editor di Visual Studio. Il metodo desiderato è EditAsync. Questo è un membro della EditorExtensibility classe , che consente l'interazione con l'editor di Visual Studio in esecuzione nell'IDE. Il Command tipo, da cui eredita la propria InsertGuidCommand classe, ha un membro Extensibility che fornisce l'accesso all'oggetto EditorExtensibility , in modo da poter accedere alla EditorExtensibility classe con una chiamata a this.Extensibility.Editor().

Il EditAsync metodo accetta come Action<IEditBatch> parametro . Questo parametro è denominato editorSource,

La chiamata a EditAsync usa un'espressione lambda. Per suddividere questo aspetto, è anche possibile scrivere tale chiamata come indicato di seguito:

await this.Extensibility.Editor().EditAsync(
    batch =>
    {
        var editor = textView.Document.AsEditable(batch);
        // specify the desired changes here:
        editor.Replace(textView.Selection.Extent, newGuidString);
    },
    cancellationToken);

È possibile considerare questa chiamata come specificare il codice che si vuole eseguire nel processo dell'editor di Visual Studio. L'espressione lambda specifica ciò che si desidera modificare nell'editor. batch è di tipo IEditBatch, che implica che l'espressione lambda definita in questo caso apporta un piccolo set di modifiche che devono essere eseguite come unità, anziché essere interrotte da altre modifiche da parte dell'utente o del servizio di linguaggio. Se il codice viene eseguito troppo a lungo, ciò può causare la mancata risposta, quindi è importante mantenere limitate le modifiche all'interno di questa espressione lambda e comprendere tutto ciò che potrebbe causare ritardi.

Usando il AsEditable metodo nel documento, si ottiene un oggetto editor temporaneo che è possibile utilizzare per specificare le modifiche desiderate. Si consideri tutto ciò che si trova nell'espressione lambda come una richiesta per l'esecuzione di Visual Studio anziché come effettivamente in esecuzione, perché come descritto in Usare l'estendibilità dell'editor di Visual Studio, esiste un particolare protocollo per gestire queste richieste di modifica asincrone dalle estensioni ed è possibile che le modifiche non vengano accettate, ad esempio se l'utente sta apportando modifiche contemporaneamente che creano un conflitto.

Il EditAsync modello può essere usato per modificare il testo in generale specificando le modifiche dopo il commento "specificare le modifiche desiderate qui".