Создание простого расширения
В разделе "Создание первого расширения" вы узнали, как использовать шаблон проекта VisualStudio.Extensibility для создания проекта расширения и узнали, как создать его и отладить в экспериментальном экземпляре Visual Studio.
В этом руководстве описано, как создать расширение с помощью простой команды, которая выполняет что-то в редакторе Visual Studio. В этом случае он вставляет только что созданный GUID. Вы также узнаете, как сообщить Visual Studio о том, какие типы файлов включено расширение GUID, и как создать новую команду в виде панели инструментов или элемента меню.
Полный пример для этого руководства можно найти здесь.
В этом руководстве приведены следующие действия.
Настройка команды
На этом шаге вы узнаете о параметрах настройки и размещения команды. Цель размещения команды заключается в том, чтобы предоставить его пользователю каким-то образом, например добавить пункт меню или кнопку панели команд.
Шаблон проекта или пример, созданный в руководстве по созданию первого расширения , состоит из одного файла C#, который уже включает Command
класс. Это можно обновить.
Переименуйте
Command1.cs
файлInsertGuidCommand.cs
в , переименуйте классInsertGuidCommand
, обновитеCommandConfiguration
свойство.public override CommandConfiguration CommandConfiguration => new("%InsertGuidCommand.DisplayName%") { Placements = new[] { CommandPlacement.KnownPlacements.ExtensionsMenu }, };
Placements
указывает, где команда должна отображаться в интегрированной среде разработки. В этом случае команда помещается в меню "Расширения", одно из меню верхнего уровня в Visual Studio.Аргумент
CommandConfiguration
конструктора — отображаемое имя команды, которое является текстом меню. Отображаемое имя заключено символами%
, так как ссылается на строковый ресурс из.vsextension/string-resources.json
поддержки локализации.Обновите
.vsextension/string-resources.json
отображаемое имяInsertGuidCommand
.{ "InsertGuidCommand.DisplayName": "Insert new guid" }
Добавление свойства
Icon
public override CommandConfiguration CommandConfiguration => new("%InsertGuidCommand.DisplayName%") { Placements = new[] { CommandPlacement.KnownPlacements.ExtensionsMenu }, Icon = new(ImageMoniker.KnownValues.OfficeWebExtension, IconSettings.IconAndText), };
В этом случае
OfficeWebExtension
можно указать известный встроенный значок или отправить изображения для значка, как описано в командах Add Visual Studio. Второй аргумент — это перечисление, определяющее, как команда должна отображаться на панелях инструментов (помимо его места в меню).IconSettings.IconAndText
Параметр означает отображение значка и отображаемого имени рядом друг с другом.VisibleWhen
Добавьте свойство, указывающее условия, которые должны применяться для элемента, отображаемого пользователю.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, ".+"), };
Дополнительные сведения см. в разделе об использовании ограничений активации на основе правил.
Создание метода выполнения
На этом шаге вы реализуете метод команды ExecuteCommandAsync
, который определяет, что происходит, когда пользователь выбирает пункт меню или нажимает элемент на панели инструментов для команды.
Скопируйте следующий код для реализации метода.
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);
}
Первая строка проверяет аргументы, а затем мы создадим новый Guid
для последующего использования.
Затем мы создадим ITextViewSnapshot
объект ( textView
здесь) путем вызова асинхронного метода GetActiveTextViewAsync
. Маркер отмены передается для сохранения возможности отмены асинхронного запроса, но эта часть не показана в этом примере. Если мы не получаем текстовое представление успешно, мы записываем в журнал и завершаем работу, не выполняя ничего другого.
Теперь мы готовы вызвать асинхронный метод, который отправляет запрос на изменение в редактор Visual Studio. Метод, который мы хотим, — EditAsync
это . Это член EditorExtensibility
класса, который позволяет взаимодействовать с запущенным редактором Visual Studio в интегрированной среде разработки. Тип Command
, от которого наследуется собственный InsertGuidCommand
класс, имеет член Extensibility
, предоставляющий доступ к EditorExtensibility
объекту, поэтому мы можем перейти к EditorExtensibility
классу с вызовом this.Extensibility.Editor()
.
Метод EditAsync
принимает в Action<IEditBatch>
качестве параметра. Этот параметр вызывается editorSource
,
Вызов использования EditAsync
лямбда-выражения. Чтобы разбить это немного, вы также можете написать этот вызов следующим образом:
await this.Extensibility.Editor().EditAsync(
batch =>
{
var editor = textView.Document.AsEditable(batch);
// specify the desired changes here:
editor.Replace(textView.Selection.Extent, newGuidString);
},
cancellationToken);
Этот вызов можно рассматривать как указание кода, который требуется запустить в процессе редактора Visual Studio. Лямбда-выражение указывает, что нужно изменить в редакторе. IEditBatch
Типbatch
, который подразумевает, что лямбда-выражение, определенное здесь, делает небольшой набор изменений, которые должны быть выполнены как единица, а не прерваны другими изменениями пользователем или языковой службой. Если код выполняется слишком долго, это может привести к неответственности, поэтому важно сохранить изменения в этом лямбда-выражении ограничено и понять, что может привести к задержкам.
AsEditable
Используя метод документа, вы получите временный объект редактора, который можно использовать для указания нужных изменений. Думайте обо всем в лямбда-выражении как запрос на выполнение Visual Studio, а не как фактическое выполнение, так как описано в расширяемости редактора Visual Studio, существует определенный протокол для обработки этих асинхронных запросов на редактирование из расширений, и есть возможность принятия изменений, например, если пользователь вносит изменения в то же время, что создает конфликт.
Шаблон EditAsync
можно использовать для изменения текста в целом, указав изменения после комментария "указать нужные изменения здесь".