Návod: Použití klávesové zkratky s rozšířením editoru

V rozšíření editoru můžete reagovat na klávesové zkratky. Následující názorný postup ukazuje, jak přidat doplněk zobrazení do textového zobrazení pomocí klávesové zkratky. Tento názorný postup je založený na šabloně editoru doplňků výřezu a umožňuje přidat doplňkovou ozdobu pomocí znaku + .

Vytvoření projektu MEF (Managed Extensibility Framework)

  1. Vytvořte projekt VSIX jazyka C#. (V Dialogové okno Nový projekt , vyberte Visual C# / Rozšiřitelnost a pak projekt VSIX.) Pojmenujte řešení KeyBindingTest.

  2. Přidejte do projektu šablonu položky doplňku text editoru a pojmenujte ji KeyBindingTest. Další informace naleznete v tématu Vytvoření rozšíření pomocí šablony položky editoru.

  3. Přidejte následující odkazy a nastavte CopyLocal na false:

    Microsoft.VisualStudio.Editor

    Microsoft.VisualStudio.OLE.Interop

    Microsoft.VisualStudio.Shell.14.0

    Microsoft.VisualStudio.TextManager.Interop

    V souboru třídy KeyBindingTest změňte název třídy na PurpleCornerBox. K provedení dalších vhodných změn použijte žárovku, která se zobrazí na levém okraji. V konstruktoru změňte název vrstvy doplňku z KeyBindingTest na PurpleCornerBox:

this.layer = view.GetAdornmentLayer("PurpleCornerBox");

V souboru třídy KeyBindingTestTextViewCreationListener.cs změňte název AdornmentLayer z KeyBindingTest na PurpleCornerBox:

[Export(typeof(AdornmentLayerDefinition))]
[Name("PurpleCornerBox")]
[Order(After = PredefinedAdornmentLayers.Selection, Before = PredefinedAdornmentLayers.Text)]
public AdornmentLayerDefinition editorAdornmentLayer;

Zpracování příkazu TYPECHAR

Před sadou Visual Studio 2017 verze 15.6 byl jediný způsob, jak zpracovat příkazy v rozšíření editoru IOleCommandTarget , implementoval založený filtr příkazů. Visual Studio 2017 verze 15.6 zavedlo moderní zjednodušený přístup založený na obslužných rutinách příkazů editoru. Následující dvě části ukazují, jak zpracovat příkaz pomocí starší verze i moderního přístupu.

Definování filtru příkazů (před sadou Visual Studio 2017 verze 15.6)

Filtr příkazu je implementace IOleCommandTarget, která zpracovává příkaz vytvořením instance doplňku.

  1. Přidejte soubor třídy a pojmenujte ho KeyBindingCommandFilter.

  2. Přidejte následující direktivy using.

    using System;
    using System.Runtime.InteropServices;
    using Microsoft.VisualStudio.OLE.Interop;
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.Text.Editor;
    
    
  3. Třída s názvem KeyBindingCommandFilter by měla dědit z IOleCommandTarget.

    internal class KeyBindingCommandFilter : IOleCommandTarget
    
  4. Přidejte soukromá pole pro textové zobrazení, další příkaz v řetězci příkazů a příznak, který představuje, jestli už byl přidán filtr příkazů.

    private IWpfTextView m_textView;
    internal IOleCommandTarget m_nextTarget;
    internal bool m_added;
    internal bool m_adorned;
    
  5. Přidejte konstruktor, který nastaví textové zobrazení.

    public KeyBindingCommandFilter(IWpfTextView textView)
    {
        m_textView = textView;
        m_adorned = false;
    }
    
  6. Implementujte metodu QueryStatus() následujícím způsobem.

    int IOleCommandTarget.QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
    {
        return m_nextTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
    }
    
  7. Implementujte metodu Exec() tak, aby přidala fialové pole do zobrazení, pokud je zadán znak plus (+).

    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);
    }
    
    

Přidání filtru příkazů (před sadou Visual Studio 2017 verze 15.6)

Zprostředkovatel doplňku musí do textového zobrazení přidat filtr příkazů. V tomto příkladu zprostředkovatel implementuje IVsTextViewCreationListener naslouchání událostem vytváření textového zobrazení. Tento zprostředkovatel doplňků také exportuje vrstvu doplňku, která definuje pořadí vykreslování doplňku.

  1. Do souboru KeyBindingTestTextViewCreationListener přidejte následující direktivy 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;
    
    
  2. Chcete-li získat adaptér textového zobrazení, je nutné importovat IVsEditorAdaptersFactoryService.

    [Import(typeof(IVsEditorAdaptersFactoryService))]
    internal IVsEditorAdaptersFactoryService editorFactory = null;
    
    
  3. Změňte metodu TextViewCreated tak, aby přidala KeyBindingCommandFilter.

    public void TextViewCreated(IWpfTextView textView)
    {
        AddCommandFilter(textView, new KeyBindingCommandFilter(textView));
    }
    
  4. Obslužná rutina AddCommandFilter získá adaptér textového zobrazení a přidá filtr příkazů.

    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;
            }
        }
    }
    

Implementace obslužné rutiny příkazu (počínaje sadou Visual Studio 2017 verze 15.6)

Nejprve aktualizujte odkazy na NuGet projektu tak, aby odkazy na nejnovější rozhraní API editoru:

  1. Klikněte pravým tlačítkem na projekt a vyberte Spravovat balíčky NuGet.

  2. V Správce balíčků NuGet vyberte kartu Aktualizace, zaškrtněte políčko Vybrat všechny balíčky a pak vyberte Aktualizovat.

Obslužná rutina příkazu je implementace ICommandHandler<T>, která zpracovává příkaz vytvořením instance doplňku.

  1. Přidejte soubor třídy a pojmenujte ho KeyBindingCommandHandler.

  2. Přidejte následující direktivy 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;
    
  3. Třída s názvem KeyBindingCommandHandler by měla dědit z ICommandHandler<TypeCharCommandArgs>a exportovat ji jako ICommandHandler:

    [Export(typeof(ICommandHandler))]
    [ContentType("text")]
    [Name("KeyBindingTest")]
    internal class KeyBindingCommandHandler : ICommandHandler<TypeCharCommandArgs>
    
  4. Přidejte zobrazovaný název obslužné rutiny příkazu:

    public string DisplayName => "KeyBindingTest";
    
  5. Implementujte metodu GetCommandState() následujícím způsobem. Protože tato obslužná rutina příkazu zpracovává základní editor TYPECHAR, může delegovat povolení příkazu do základního editoru.

    public CommandState GetCommandState(TypeCharCommandArgs args)
    {
        return CommandState.Unspecified;
    }
    
  6. Implementujte metodu ExecuteCommand() tak, aby přidala fialové pole do zobrazení, pokud je zadán znak plus (+).

    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;
    }
    
    1. Zkopírujte definici vrstvy adornmentu ze souboru KeyBindingTestTextViewCreationListener.cs do souboru KeyBindingCommandHandler.cs a odstraňte soubor 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;
    

Zobrazení doplňku na každém řádku

Původní doplněk se objevil na každém znaku "a" v textovém souboru. Teď, když jsme změnili kód pro přidání doplňku v reakci na + znak, přidá doplněk pouze na řádek, kde + je znak zadán. Kód doplňku můžeme změnit tak, aby se doplňková ozdoba objevila na každém znaku "a".

V souboru KeyBindingTest.cs změňte metodu CreateVisuals() iterace všemi řádky v zobrazení tak, aby ozdobila znak "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);
                    }
                }
            }
        }
    }
}

Sestavení a otestování kódu

  1. Sestavte řešení KeyBindingTest a spusťte ho v experimentální instanci.

  2. Vytvořte nebo otevřete textový soubor. Zadejte některá slova obsahující znak "a" a potom zadejte + libovolné místo v textovém zobrazení.

    Na každém znaku "a" v souboru by se měl objevit fialový čtverec.