Creación de una extensión sencilla

En Creación de la primera extensión, ha aprendido a usar la plantilla de proyecto VisualStudio.Extensibility para crear un proyecto de extensión y ha aprendido a compilarla y depurarla en la instancia experimental de Visual Studio.

En este tutorial, aprenderá a crear una extensión con un comando sencillo que haga algo en el editor de Visual Studio. En este caso, inserta un GUID recién generado. También verá cómo indicar a Visual Studio qué tipos de archivo está habilitada la extensión GUID y cómo hacer que el nuevo comando aparezca como un elemento de menú o barra de herramientas.

El ejemplo completado de este tutorial puede encontrarse aquí.

El tutorial contiene los pasos siguientes:

Configuración del comando

En este paso, obtendrá información sobre las opciones para configurar y colocar el comando. El propósito de hospedar el comando es exponerlo al usuario de alguna manera, como agregar un elemento de menú o un botón de barra de comandos.

La plantilla de proyecto o el ejemplo que creó en el tutorial Creación de la primera extensión consta de un único archivo de C# que incluye una Command clase ya. Puede actualizarlo en su lugar.

  1. Cambie el nombre del Command1.cs archivo a InsertGuidCommand.cs, cambie el nombre de la clase InsertGuidCommandy actualice la CommandConfiguration propiedad .

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

    Placements especifica dónde debe aparecer el comando en el IDE. En este caso, el comando se coloca en el menú Extensiones, uno de los menús de nivel superior de Visual Studio.

    El argumento para el CommandConfiguration constructor es el nombre para mostrar del comando, que es el texto del menú. El nombre para mostrar se incluye entre % caracteres porque hace referencia a un recurso de cadena de .vsextension/string-resources.json para admitir la localización.

  2. Actualice .vsextension/string-resources.json con el nombre para mostrar de InsertGuidCommand.

    {
      "InsertGuidCommand.DisplayName": "Insert new guid"
    }
    
  3. Agregue la propiedad Icon.

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

    Puede especificar un icono integrado conocido, en este caso OfficeWebExtension, o cargar imágenes para el icono, tal como se describe en Agregar comandos de Visual Studio. El segundo argumento es una enumeración que determina cómo debe aparecer el comando en las barras de herramientas (además de su lugar en un menú). La opción IconSettings.IconAndText significa mostrar el icono y el nombre para mostrar junto al otro.

  4. Agregue la VisibleWhen propiedad , que especifica las condiciones que deben aplicarse para que el elemento aparezca al usuario.

    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, ".+"),
    };
    

Consulte Uso de restricciones de activación basadas en reglas para obtener más información.

Creación del método de ejecución

En este paso, implementará el método del ExecuteCommandAsync comando, que define lo que sucede cuando el usuario elige el elemento de menú, o presiona el elemento en la barra de herramientas del comando.

Copie el código siguiente para implementar el método .

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 primera línea valida los argumentos y, a continuación, creamos un nuevo Guid para usarlo más adelante.

A continuación, creamos un ITextViewSnapshot objeto (el textView objeto aquí) llamando al método GetActiveTextViewAsyncasincrónico . Se pasa un token de cancelación para conservar la capacidad de cancelar la solicitud asincrónica, pero esta parte no se muestra en este ejemplo. Si no se obtiene correctamente una vista de texto, se escribe en el registro y finaliza sin hacer nada más.

Ahora estamos listos para llamar al método asincrónico que envía una solicitud de edición al editor de Visual Studio. El método que queremos es EditAsync. Es un miembro de la EditorExtensibility clase , que permite la interacción con el Editor de Visual Studio en ejecución en el IDE. El Command tipo, de la que hereda su propia InsertGuidCommand clase, tiene un miembro Extensibility que proporciona acceso al EditorExtensibility objeto, por lo que podemos llegar a la EditorExtensibility clase con una llamada a this.Extensibility.Editor().

El EditAsync método toma como Action<IEditBatch> parámetro . Este parámetro se denomina editorSource,

La llamada a EditAsync usa una expresión lambda. Para desglosar esto un poco, también podría escribir esa llamada como se indica a continuación:

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

Puede pensar en esta llamada como especificar el código que desea ejecutar en el proceso del editor de Visual Studio. La expresión lambda especifica lo que desea cambiar en el editor. batch es de tipo IEditBatch, lo que implica que la expresión lambda definida aquí realiza un pequeño conjunto de cambios que se deben realizar como una unidad, en lugar de ser interrumpidos por otros cambios por el usuario o el servicio de lenguaje. Si el código se ejecuta demasiado tiempo, esto puede dar lugar a una falta de respuesta, por lo que es importante mantener los cambios dentro de esta expresión lambda limitado y comprender todo lo que pueda provocar retrasos.

Con el AsEditable método del documento, obtendrá un objeto de editor temporal que puede usar para especificar los cambios deseados. Piense en todo lo que hay en la expresión lambda como una solicitud para que Visual Studio se ejecute en lugar de ejecutarse realmente, ya que, como se describe en La extensibilidad del editor de Visual Studio, hay un protocolo determinado para controlar estas solicitudes de edición asincrónicas de extensiones y hay una posibilidad de que no se acepten los cambios, como si el usuario está realizando cambios al mismo tiempo que crean un conflicto.

El EditAsync patrón se puede usar para modificar el texto en general especificando las modificaciones después del comentario "especifique los cambios deseados aquí".