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.
Cambie el nombre del
Command1.cs
archivo aInsertGuidCommand.cs
, cambie el nombre de la claseInsertGuidCommand
y actualice laCommandConfiguration
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.Actualice
.vsextension/string-resources.json
con el nombre para mostrar deInsertGuidCommand
.{ "InsertGuidCommand.DisplayName": "Insert new guid" }
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ónIconSettings.IconAndText
significa mostrar el icono y el nombre para mostrar junto al otro.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 GetActiveTextViewAsync
asincró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í".