Пошаговое руководство. Использование сочетания клавиш с расширением редактора
Вы можете ответить на сочетания клавиш в расширении редактора. В следующем пошаговом руководстве показано, как добавить украшение представления в текстовое представление с помощью сочетания клавиш. Это пошаговое руководство основано на шаблоне редактора украшений окна просмотра и позволяет добавлять украшения с помощью символа +.
Создание проекта Managed Extensibility Framework (MEF)
Создайте проект VSIX на C#. (В Диалоговое окно "Новый проект" , выберите Visual C# / Расширяемость, а затем ПРОЕКТ VSIX.) Назовите решение
KeyBindingTest
.Добавьте шаблон элемента оформления текста редактора в проект и назовите его
KeyBindingTest
. Дополнительные сведения см. в разделе "Создание расширения с помощью шаблона элемента редактора".Добавьте следующие ссылки и задайте значение CopyLocal
false
:Microsoft.VisualStudio.Editor
Microsoft.VisualStudio.OLE.Interop
Microsoft.VisualStudio.Shell.14.0
Microsoft.VisualStudio.TextManager.Interop
В файле класса KeyBindingTest измените имя класса на PurpleCornerBox. Используйте лампочку, которая отображается в левом поле, чтобы внести другие соответствующие изменения. В конструкторе измените имя слоя украшения с KeyBindingTest на PurpleCornerBox:
this.layer = view.GetAdornmentLayer("PurpleCornerBox");
В файле класса KeyBindingTestTextViewCreationListener.cs измените имя Объекта AdornmentLayer с KeyBindingTest на PurpleCornerBox:
[Export(typeof(AdornmentLayerDefinition))]
[Name("PurpleCornerBox")]
[Order(After = PredefinedAdornmentLayers.Selection, Before = PredefinedAdornmentLayers.Text)]
public AdornmentLayerDefinition editorAdornmentLayer;
Обработка команды TYPECHAR
До Visual Studio 2017 версии 15.6 единственный способ обработки команд в расширении редактора реализует IOleCommandTarget фильтр на основе команд. Visual Studio 2017 версии 15.6 представила современный упрощенный подход на основе обработчиков команд редактора. В следующих двух разделах показано, как обрабатывать команду с помощью устаревшего и современного подхода.
Определение фильтра команд (до Visual Studio 2017 версии 15.6)
Фильтр команд — это реализация IOleCommandTarget, которая обрабатывает команду путем создания экземпляра украшения.
Добавьте файл класса с именем
KeyBindingCommandFilter
.Добавьте следующие директивы using.
using System; using System.Runtime.InteropServices; using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Text.Editor;
Класс с именем KeyBindingCommandFilter должен наследоваться.IOleCommandTarget
internal class KeyBindingCommandFilter : IOleCommandTarget
Добавьте частные поля для текстового представления, следующую команду в цепочке команд и флаг, который будет представлять, уже добавлен ли фильтр команд.
private IWpfTextView m_textView; internal IOleCommandTarget m_nextTarget; internal bool m_added; internal bool m_adorned;
Добавьте конструктор, который задает текстовое представление.
public KeyBindingCommandFilter(IWpfTextView textView) { m_textView = textView; m_adorned = false; }
QueryStatus()
Реализуйте метод следующим образом.int IOleCommandTarget.QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) { return m_nextTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); }
Exec()
Реализуйте метод, чтобы он добавлял фиолетовый прямоугольник в представление, если символ плюса (+) введен.int IOleCommandTarget.Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { if (m_adorned == false) { char typedChar = char.MinValue; if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR) { typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); if (typedChar.Equals('+')) { new PurpleCornerBox(m_textView); m_adorned = true; } } } return m_nextTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); }
Добавьте фильтр команд (до Visual Studio 2017 версии 15.6)
Поставщик украшений должен добавить фильтр команд в текстовое представление. В этом примере поставщик реализует IVsTextViewCreationListener прослушивание событий создания представления текста. Этот поставщик украшений также экспортирует слой украшений, который определяет порядок Z украшения.
В файле KeyBindingTestTextViewCreationListener добавьте следующие директивы using:
using System; using System.Collections.Generic; using System.ComponentModel.Composition; using Microsoft.VisualStudio; using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.Utilities; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.TextManager.Interop;
Чтобы получить адаптер текстового представления, необходимо импортировать .IVsEditorAdaptersFactoryService
[Import(typeof(IVsEditorAdaptersFactoryService))] internal IVsEditorAdaptersFactoryService editorFactory = null;
Измените TextViewCreated метод таким образом, чтобы он добавил
KeyBindingCommandFilter
.public void TextViewCreated(IWpfTextView textView) { AddCommandFilter(textView, new KeyBindingCommandFilter(textView)); }
Обработчик
AddCommandFilter
получает адаптер представления текста и добавляет фильтр команд.void AddCommandFilter(IWpfTextView textView, KeyBindingCommandFilter commandFilter) { if (commandFilter.m_added == false) { //get the view adapter from the editor factory IOleCommandTarget next; IVsTextView view = editorFactory.GetViewAdapter(textView); int hr = view.AddCommandFilter(commandFilter, out next); if (hr == VSConstants.S_OK) { commandFilter.m_added = true; //you'll need the next target for Exec and QueryStatus if (next != null) commandFilter.m_nextTarget = next; } } }
Реализация обработчика команд (начиная с Visual Studio 2017 версии 15.6)
Сначала обновите ссылки nuget проекта, чтобы ссылаться на последний API редактора:
Щелкните проект правой кнопкой мыши и выберите пункт "Управление пакетами Nuget".
В диспетчер пакетов Nuget перейдите на вкладку Обновления, выберите пункт "Выбрать все пакеты проверка", а затем нажмите кнопку "Обновить".
Обработчик команд — это реализация ICommandHandler<T>, которая обрабатывает команду путем создания экземпляра украшения.
Добавьте файл класса с именем
KeyBindingCommandHandler
.Добавьте следующие директивы using.
using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Utilities; using System.ComponentModel.Composition;
Класс с именем KeyBindingCommandHandler должен наследоваться от
ICommandHandler<TypeCharCommandArgs>
и экспортировать его как ICommandHandler:[Export(typeof(ICommandHandler))] [ContentType("text")] [Name("KeyBindingTest")] internal class KeyBindingCommandHandler : ICommandHandler<TypeCharCommandArgs>
Добавьте отображаемое имя обработчика команд:
public string DisplayName => "KeyBindingTest";
GetCommandState()
Реализуйте метод следующим образом. Так как этот обработчик команд обрабатывает команду TYPECHAR для основного редактора, он может делегировать включение команды в основной редактор.public CommandState GetCommandState(TypeCharCommandArgs args) { return CommandState.Unspecified; }
ExecuteCommand()
Реализуйте метод, чтобы он добавлял фиолетовый прямоугольник в представление, если символ плюса (+) введен.public bool ExecuteCommand(TypeCharCommandArgs args, CommandExecutionContext executionContext) { if (args.TypedChar == '+') { bool alreadyAdorned = args.TextView.Properties.TryGetProperty( "KeyBindingTextAdorned", out bool adorned) && adorned; if (!alreadyAdorned) { new PurpleCornerBox((IWpfTextView)args.TextView); args.TextView.Properties.AddProperty("KeyBindingTextAdorned", true); } } return false; }
- Скопируйте определение слоя украшений из файла KeyBindingTestTextCreationListener.cs в файл KeyBindingCommandHandler.cs, а затем удалите файл KeyBindingTestTextViewCreationListener.cs:
/// <summary> /// Defines the adornment layer for the adornment. This layer is ordered /// after the selection layer in the Z-order. /// </summary> [Export(typeof(AdornmentLayerDefinition))] [Name("PurpleCornerBox")] [Order(After = PredefinedAdornmentLayers.Selection, Before = PredefinedAdornmentLayers.Text)] private AdornmentLayerDefinition editorAdornmentLayer;
Сделать украшение появляется на каждой строке
Первоначальное украшение появилось на каждом символе "a" в текстовом файле. Теперь, когда мы изменили код, чтобы добавить украшение в ответ + на символ, он добавляет украшение только в строке, где + символ вводится. Мы можем изменить код украшения, чтобы украшение еще раз появлялось на каждом "a".
В файле KeyBindingTest.cs измените CreateVisuals()
метод, чтобы итерировать все строки в представлении, чтобы украсить символ a.
private void CreateVisuals(ITextViewLine line)
{
IWpfTextViewLineCollection textViewLines = this.view.TextViewLines;
foreach (ITextViewLine textViewLine in textViewLines)
{
if (textViewLine.ToString().Contains("a"))
{
// Loop through each character, and place a box around any 'a'
for (int charIndex = textViewLine.Start; charIndex < textViewLine.End; charIndex++)
{
if (this.view.TextSnapshot[charIndex] == 'a')
{
SnapshotSpan span = new SnapshotSpan(this.view.TextSnapshot, Span.FromBounds(charIndex, charIndex + 1));
Geometry geometry = textViewLines.GetMarkerGeometry(span);
if (geometry != null)
{
var drawing = new GeometryDrawing(this.brush, this.pen, geometry);
drawing.Freeze();
var drawingImage = new DrawingImage(drawing);
drawingImage.Freeze();
var image = new Image
{
Source = drawingImage,
};
// Align the image with the top of the bounds of the text geometry
Canvas.SetLeft(image, geometry.Bounds.Left);
Canvas.SetTop(image, geometry.Bounds.Top);
this.layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, span, null, image, null);
}
}
}
}
}
}
Сборка и проверка кода
Создайте решение KeyBindingTest и запустите его в экспериментальном экземпляре.
Создайте или откройте текстовый файл. Введите некоторые слова, содержащие символ "a", а затем введите + в любом месте текстового представления.
Фиолетовый квадрат должен отображаться на каждом символе "a" в файле.