Exemplarische Vorgehensweise: Anzeigen der Signaturhilfe

Die Signaturhilfe (auch als Parameterinformationen bezeichnet) zeigt die Signatur einer Methode in einer QuickInfo an, wenn ein Benutzer das Startzeichen der Parameterliste eingibt (in der Regel eine öffnende Klammer). Da ein Parameter und ein Parametertrennzeichen (in der Regel ein Komma) eingegeben werden, wird die QuickInfo aktualisiert, um den nächsten Parameter fett zu zeigen. Sie können die Signaturhilfe auf folgende Weise definieren: Definieren Sie im Kontext eines Sprachdiensts Ihre eigene Dateinamenerweiterung und den Inhaltstyp, und zeigen Sie die Signaturhilfe nur für diesen Typ an, oder zeigen Sie die Signaturhilfe für einen vorhandenen Inhaltstyp an (z. B. "text"). In dieser exemplarischen Vorgehensweise wird gezeigt, wie die Signaturhilfe für den Inhaltstyp "text" angezeigt wird.

Die Signaturhilfe wird in der Regel durch Eingabe eines bestimmten Zeichens ausgelöst, z. B. "(" (öffnende Klammer) und durch Eingabe eines anderen Zeichens, z. B. ")" (schließende Klammer). IntelliSense-Features, die durch Eingabe eines Zeichens ausgelöst werden, können implementiert werden, indem ein Befehlshandler für die Tastatureingaben (die IOleCommandTarget Schnittstelle) und ein Handleranbieter verwendet werden, der die IVsTextViewCreationListener Schnittstelle implementiert. Implementieren Sie die -Schnittstelle und einen Quellanbieter, der die -Schnittstelle ausführt, um die Signaturhilfequelle zu erstellen, bei der es sich um die Liste der Signaturen handelt, die an der Signaturhilfe beteiligt ISignatureHelpSource ISignatureHelpSourceProvider sind. Die Anbieter sind Managed Extensibility Framework Komponententeile (MEF) und sind für den Export der Quell- und Controllerklassen und das Importieren von Diensten und Brokern verantwortlich, z. B. , mit dem ITextStructureNavigatorSelectorService Sie im Textpuffer navigieren können, und für den , der ISignatureHelpBroker die Signaturhilfesitzung auslöst.

In dieser exemplarischen Vorgehensweise wird gezeigt, wie Sie die Signaturhilfe für einen hart codierten Satz von Bezeichnern einrichten. In vollständigen Implementierungen ist die Sprache für die Bereitstellung dieser Inhalte verantwortlich.

Voraussetzungen

Ab Visual Studio 2015 installieren Sie das Visual Studio SDK nicht mehr aus dem Download Center. Es ist als optionales Feature in Visual Studio-Setup enthalten. Sie können das VS SDK auch später installieren. Weitere Informationen finden Sie unter Installieren des Visual Studio SDK.

Erstellen eines MEF-Projekts

So erstellen Sie ein MEF-Projekt

  1. Erstellen Sie ein C#-VSIX-Projekt. (Wählen Sie im Dialogfeld New Project (Neue Project) Visual C# /Extensibility und dann VSIX Project aus.) Nennen Sie die Projektmappe SignatureHelpTest .

  2. Fügen Sie dem Projekt eine Editor-Klassifizierungselementvorlage hinzu. Weitere Informationen finden Sie unter Erstellen einer Erweiterung mit einer Editorelementvorlage.

  3. Löschen Sie die vorhandenen Klassendateien.

  4. Fügen Sie dem Projekt die folgenden Verweise hinzu, und stellen Sie sicher, dass CopyLocal auf festgelegt false ist:

    Microsoft.VisualStudio.Editor

    Microsoft.VisualStudio.Language.Intellisense

    Microsoft.VisualStudio.OLE.Interop

    Microsoft.VisualStudio.Shell.14.0

    Microsoft.VisualStudio.TextManager.Interop

Implementieren von Signaturenhilfesignaturen und Parametern

Die Signaturhilfequelle basiert auf Signaturen, die ISignature implementieren, von denen jeder Parameter enthält, die IParameter implementieren. In einer vollständigen Implementierung würden diese Informationen aus der Sprachdokumentation abgerufen, aber in diesem Beispiel sind die Signaturen hart codiert.

So implementieren Sie Signaturen und Parameter der Signaturhilfe

  1. Fügen Sie eine Klassendatei hinzu, und nennen Sie sie SignatureHelpSource.

  2. Fügen Sie die folgenden Importe hinzu.

    Imports System
    Imports System.Collections.Generic
    Imports System.Linq
    Imports System.Text
    Imports System.Collections.ObjectModel
    Imports System.ComponentModel.Composition
    Imports System.Runtime.InteropServices
    Imports Microsoft.VisualStudio.Language.Intellisense
    Imports Microsoft.VisualStudio.Text
    Imports Microsoft.VisualStudio.Text.Editor
    Imports Microsoft.VisualStudio.Utilities
    Imports Microsoft.VisualStudio.Editor
    Imports Microsoft.VisualStudio.Text.Operations
    Imports Microsoft.VisualStudio
    Imports Microsoft.VisualStudio.TextManager.Interop
    Imports Microsoft.VisualStudio.OLE.Interop
    
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel.Composition;
    using System.Runtime.InteropServices;
    using Microsoft.VisualStudio.Language.Intellisense;
    using Microsoft.VisualStudio.Text;
    using Microsoft.VisualStudio.Text.Editor;
    using Microsoft.VisualStudio.Utilities;
    using Microsoft.VisualStudio.Editor;
    using Microsoft.VisualStudio.Text.Operations;
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.TextManager.Interop;
    using Microsoft.VisualStudio.OLE.Interop;
    
  3. Fügen Sie eine Klasse namens TestParameter hinzu, die IParameter implementiert.

    Friend Class TestParameter
        Implements IParameter
    
    internal class TestParameter : IParameter
    
  4. Fügen Sie einen Konstruktor hinzu, der alle Eigenschaften festlegt.

    Public Sub New(ByVal documentation As String, ByVal locus As Span, ByVal name As String, ByVal signature As ISignature)
        Me.privateDocumentation = documentation
        Me.privateLocus = locus
        Me.privateName = name
        Me.privateSignature = signature
    End Sub
    
    public TestParameter(string documentation, Span locus, string name, ISignature signature)
    {
        Documentation = documentation;
        Locus = locus;
        Name = name;
        Signature = signature;
    }
    
  5. Fügen Sie die Eigenschaften von IParameter hinzu.

    Private privateDocumentation As String
    ReadOnly Property Documentation() As String Implements IParameter.Documentation
        Get
            Return privateDocumentation
        End Get
    
    End Property
    Private privateLocus As Span
    ReadOnly Property Locus() As Span Implements IParameter.Locus
        Get
            Return privateLocus
        End Get
    End Property
    Private privateName As String
    ReadOnly Property Name() As String Implements IParameter.Name
        Get
            Return privateName
        End Get
    End Property
    Private privateSignature As ISignature
    ReadOnly Property Signature() As ISignature Implements IParameter.Signature
        Get
            Return privateSignature
        End Get
    End Property
    Private privatePrettyPrintedLocus As Span
    ReadOnly Property PrettyPrintedLocus() As Span Implements IParameter.PrettyPrintedLocus
        Get
            Return privatePrettyPrintedLocus
        End Get
    End Property
    
    public string Documentation { get; private set; }
    public Span Locus { get; private set; }
    public string Name { get; private set; }
    public ISignature Signature { get; private set; }
    public Span PrettyPrintedLocus { get; private set; }
    
  6. Fügen Sie eine Klasse namens TestSignature hinzu, die ISignature implementiert.

    Friend Class TestSignature
        Implements ISignature
    
    internal class TestSignature : ISignature
    
  7. Fügen Sie einige private Felder hinzu.

    Private m_subjectBuffer As ITextBuffer
    Private m_currentParameter As IParameter
    Private m_content As String
    Private m_documentation As String
    Friend m_applicableToSpan As ITrackingSpan
    Friend m_parameters As ReadOnlyCollection(Of IParameter)
    Private m_printContent As String
    
    private ITextBuffer m_subjectBuffer;
    private IParameter m_currentParameter;
    private string m_content;
    private string m_documentation;
    private ITrackingSpan m_applicableToSpan;
    private ReadOnlyCollection<IParameter> m_parameters;
    private string m_printContent;
    
  8. Fügen Sie einen Konstruktor hinzu, der die Felder festlegt und das Ereignis abonniert. Changed

    Friend Sub New(ByVal subjectBuffer As ITextBuffer, ByVal content As String, ByVal doc As String, ByVal parameters As ReadOnlyCollection(Of IParameter))
        m_subjectBuffer = subjectBuffer
        m_content = content
        m_documentation = doc
        m_parameters = parameters
        AddHandler m_subjectBuffer.Changed, AddressOf OnSubjectBufferChanged
    End Sub
    
    internal TestSignature(ITextBuffer subjectBuffer, string content, string doc, ReadOnlyCollection<IParameter> parameters)
    {
        m_subjectBuffer = subjectBuffer;
        m_content = content;
        m_documentation = doc;
        m_parameters = parameters;
        m_subjectBuffer.Changed += new EventHandler<TextContentChangedEventArgs>(OnSubjectBufferChanged);
    }
    
  9. Deklarieren Sie ein CurrentParameterChanged Ereignis. Dieses Ereignis wird ausgelöst, wenn der Benutzer einen der Parameter in der Signatur einfüllt.

    Public Event CurrentParameterChanged As EventHandler(Of CurrentParameterChangedEventArgs) Implements ISignature.CurrentParameterChanged
    
    public event EventHandler<CurrentParameterChangedEventArgs> CurrentParameterChanged;
    
  10. Implementieren Sie die CurrentParameter -Eigenschaft, sodass sie das CurrentParameterChanged -Ereignis auslöst, wenn der Eigenschaftswert geändert wird.

    ReadOnly Property CurrentParameter() As IParameter Implements ISignature.CurrentParameter
        Get
            Return m_currentParameter
        End Get
    End Property
    
    public IParameter CurrentParameter
    {
        get { return m_currentParameter; }
        internal set
        {
            if (m_currentParameter != value)
            {
                IParameter prevCurrentParameter = m_currentParameter;
                m_currentParameter = value;
                this.RaiseCurrentParameterChanged(prevCurrentParameter, m_currentParameter);
            }
        }
    }
    
  11. Fügen Sie eine Methode hinzu, die das CurrentParameterChanged -Ereignis auslöst.

    Private Sub RaiseCurrentParameterChanged(ByVal prevCurrentParameter As IParameter, ByVal newCurrentParameter As IParameter)
        Dim tempHandler As EventHandler(Of CurrentParameterChangedEventArgs) = Me.CurrentParameterChangedEvent
        If tempHandler IsNot Nothing Then
            tempHandler(Me, New CurrentParameterChangedEventArgs(prevCurrentParameter, newCurrentParameter))
        End If
    End Sub
    
    private void RaiseCurrentParameterChanged(IParameter prevCurrentParameter, IParameter newCurrentParameter)
    {
        EventHandler<CurrentParameterChangedEventArgs> tempHandler = this.CurrentParameterChanged;
        if (tempHandler != null)
        {
            tempHandler(this, new CurrentParameterChangedEventArgs(prevCurrentParameter, newCurrentParameter));
        }
    }
    
  12. Fügen Sie eine Methode hinzu, die den aktuellen Parameter berechnet, indem Sie die Anzahl der Kommas in der ApplicableToSpan mit der Anzahl der Kommas in der Signatur vergleichen.

    Friend Sub ComputeCurrentParameter()
        If Parameters.Count = 0 Then
            Me.m_currentParameter = Nothing
            Return
        End If
    
        'the number of commas in the string is the index of the current parameter
        Dim sigText As String = ApplicableToSpan.GetText(m_subjectBuffer.CurrentSnapshot)
    
        Dim currentIndex As Integer = 0
        Dim commaCount As Integer = 0
        Do While currentIndex < sigText.Length
            Dim commaIndex As Integer = sigText.IndexOf(","c, currentIndex)
            If commaIndex = -1 Then
                Exit Do
            End If
            commaCount += 1
            currentIndex = commaIndex + 1
        Loop
    
        If commaCount < Parameters.Count Then
            Me.m_currentParameter = Parameters(commaCount)
        Else
            'too many commas, so use the last parameter as the current one.
            Me.m_currentParameter = Parameters(Parameters.Count - 1)
        End If
    End Sub
    
    internal void ComputeCurrentParameter()
    {
        if (Parameters.Count == 0)
        {
            this.CurrentParameter = null;
            return;
        }
    
        //the number of commas in the string is the index of the current parameter
        string sigText = ApplicableToSpan.GetText(m_subjectBuffer.CurrentSnapshot);
    
        int currentIndex = 0;
        int commaCount = 0;
        while (currentIndex < sigText.Length)
        {
            int commaIndex = sigText.IndexOf(',', currentIndex);
            if (commaIndex == -1)
            {
                break;
            }
            commaCount++;
            currentIndex = commaIndex + 1;
        }
    
        if (commaCount < Parameters.Count)
        {
            this.CurrentParameter = Parameters[commaCount];
        }
        else
        {
            //too many commas, so use the last parameter as the current one.
            this.CurrentParameter = Parameters[Parameters.Count - 1];
        }
    }
    
  13. Fügen Sie einen Ereignishandler für das Changed Ereignis hinzu, das die ComputeCurrentParameter() -Methode aufruft.

    Friend Sub OnSubjectBufferChanged(ByVal sender As Object, ByVal e As TextContentChangedEventArgs)
        Me.ComputeCurrentParameter()
    End Sub
    
    internal void OnSubjectBufferChanged(object sender, TextContentChangedEventArgs e)
    {
        this.ComputeCurrentParameter();
    }
    
  14. Implementiert die ApplicableToSpan-Eigenschaft. Diese Eigenschaft enthält eine , ITrackingSpan die der Textspanne im Puffer entspricht, für den die Signatur gilt.

    ReadOnly Property ApplicableToSpan() As ITrackingSpan Implements ISignature.ApplicableToSpan
        Get
            Return (m_applicableToSpan)
        End Get
    End Property
    
    public ITrackingSpan ApplicableToSpan
    {
        get { return (m_applicableToSpan); }
        internal set { m_applicableToSpan = value; }
    }
    
  15. Implementieren Sie die anderen Parameter.

    ReadOnly Property Content() As String Implements ISignature.Content
        Get
            Return (m_content)
        End Get
    End Property
    
    ReadOnly Property Documentation() As String Implements ISignature.Documentation
        Get
            Return (m_documentation)
        End Get
    End Property
    
    ReadOnly Property Parameters() As ReadOnlyCollection(Of IParameter) Implements ISignature.Parameters
        Get
            Return (m_parameters)
        End Get
    End Property
    
    ReadOnly Property PrettyPrintedContent() As String Implements ISignature.PrettyPrintedContent
        Get
            Return (m_printContent)
        End Get
    End Property
    
    public string Content
    {
        get { return (m_content); }
        internal set { m_content = value; }
    }
    
    public string Documentation
    {
        get { return (m_documentation); }
        internal set { m_documentation = value; }
    }
    
    public ReadOnlyCollection<IParameter> Parameters
    {
        get { return (m_parameters); }
        internal set { m_parameters = value; }
    }
    
    public string PrettyPrintedContent
    {
        get { return (m_printContent); }
        internal set { m_printContent = value; }
    }
    

Implementieren der Signaturhilfequelle

Die Signaturhilfequelle ist der Satz von Signaturen, für den Sie Informationen bereitstellen.

So implementieren Sie die Signaturhilfequelle

  1. Fügen Sie eine Klasse namens TestSignatureHelpSource hinzu, die ISignatureHelpSource implementiert.

    Friend Class TestSignatureHelpSource
        Implements ISignatureHelpSource
    
    internal class TestSignatureHelpSource : ISignatureHelpSource
    
  2. Fügen Sie einen Verweis auf den Textpuffer hinzu.

    Private m_textBuffer As ITextBuffer
    
    private ITextBuffer m_textBuffer;
    
  3. Fügen Sie einen Konstruktor hinzu, der den Textpuffer und den Signaturhilfe-Quellanbieter festlegt.

    Public Sub New(ByVal textBuffer As ITextBuffer)
        m_textBuffer = textBuffer
    End Sub
    
    public TestSignatureHelpSource(ITextBuffer textBuffer)
    {
        m_textBuffer = textBuffer;
    }
    
  4. Implementieren Sie die AugmentSignatureHelpSession-Methode. In diesem Beispiel sind die Signaturen hart codiert, aber in einer vollständigen Implementierung erhalten Sie diese Informationen aus der Sprachdokumentation.

    Public Sub AugmentSignatureHelpSession(ByVal session As ISignatureHelpSession, ByVal signatures As IList(Of ISignature)) Implements ISignatureHelpSource.AugmentSignatureHelpSession
        Dim snapshot As ITextSnapshot = m_textBuffer.CurrentSnapshot
        Dim position As Integer = session.GetTriggerPoint(m_textBuffer).GetPosition(snapshot)
    
        Dim applicableToSpan As ITrackingSpan = m_textBuffer.CurrentSnapshot.CreateTrackingSpan(New Span(position, 0), SpanTrackingMode.EdgeInclusive, 0)
    
        signatures.Add(CreateSignature(m_textBuffer, "add(int firstInt, int secondInt)", "Documentation for adding integers.", applicableToSpan))
        signatures.Add(CreateSignature(m_textBuffer, "add(double firstDouble, double secondDouble)", "Documentation for adding doubles.", applicableToSpan))
    End Sub
    
    public void AugmentSignatureHelpSession(ISignatureHelpSession session, IList<ISignature> signatures)
    {
        ITextSnapshot snapshot = m_textBuffer.CurrentSnapshot;
        int position = session.GetTriggerPoint(m_textBuffer).GetPosition(snapshot);
    
        ITrackingSpan applicableToSpan = m_textBuffer.CurrentSnapshot.CreateTrackingSpan(
         new Span(position, 0), SpanTrackingMode.EdgeInclusive, 0);
    
        signatures.Add(CreateSignature(m_textBuffer, "add(int firstInt, int secondInt)", "Documentation for adding integers.", applicableToSpan));
        signatures.Add(CreateSignature(m_textBuffer, "add(double firstDouble, double secondDouble)", "Documentation for adding doubles.", applicableToSpan));
    
    }
    
  5. Die Hilfsmethode CreateSignature() wird nur zur Veranschaulichung bereitgestellt.

    Private Function CreateSignature(ByVal textBuffer As ITextBuffer, ByVal methodSig As String, ByVal methodDoc As String, ByVal span As ITrackingSpan) As TestSignature
        Dim sig As New TestSignature(textBuffer, methodSig, methodDoc, Nothing)
        AddHandler textBuffer.Changed, AddressOf sig.OnSubjectBufferChanged
    
        'find the parameters in the method signature (expect methodname(one, two)
        Dim pars() As String = methodSig.Split(New Char() {"("c, ","c, ")"c})
        Dim paramList As New List(Of IParameter)()
    
        Dim locusSearchStart As Integer = 0
        For i As Integer = 1 To pars.Length - 1
            Dim param As String = pars(i).Trim()
    
            If String.IsNullOrEmpty(param) Then
                Continue For
            End If
    
            'find where this parameter is located in the method signature
            Dim locusStart As Integer = methodSig.IndexOf(param, locusSearchStart)
            If locusStart >= 0 Then
                Dim locus As New Span(locusStart, param.Length)
                locusSearchStart = locusStart + param.Length
                paramList.Add(New TestParameter("Documentation for the parameter.", locus, param, sig))
            End If
        Next i
    
        sig.m_Parameters = New ReadOnlyCollection(Of IParameter)(paramList)
        sig.m_ApplicableToSpan = span
        sig.ComputeCurrentParameter()
        Return sig
    End Function
    
    private TestSignature CreateSignature(ITextBuffer textBuffer, string methodSig, string methodDoc, ITrackingSpan span)
    {
        TestSignature sig = new TestSignature(textBuffer, methodSig, methodDoc, null);
        textBuffer.Changed += new EventHandler<TextContentChangedEventArgs>(sig.OnSubjectBufferChanged);
    
        //find the parameters in the method signature (expect methodname(one, two)
        string[] pars = methodSig.Split(new char[] { '(', ',', ')' });
        List<IParameter> paramList = new List<IParameter>();
    
        int locusSearchStart = 0;
        for (int i = 1; i < pars.Length; i++)
        {
            string param = pars[i].Trim();
    
            if (string.IsNullOrEmpty(param))
                continue;
    
            //find where this parameter is located in the method signature
            int locusStart = methodSig.IndexOf(param, locusSearchStart);
            if (locusStart >= 0)
            {
                Span locus = new Span(locusStart, param.Length);
                locusSearchStart = locusStart + param.Length;
                paramList.Add(new TestParameter("Documentation for the parameter.", locus, param, sig));
            }
        }
    
        sig.Parameters = new ReadOnlyCollection<IParameter>(paramList);
        sig.ApplicableToSpan = span;
        sig.ComputeCurrentParameter();
        return sig;
    }
    
  6. Implementieren Sie die GetBestMatch-Methode. In diesem Beispiel gibt es nur zwei Signaturen, von denen jede über zwei Parameter verfügt. Daher ist diese Methode nicht erforderlich. In einer vollständigeren Implementierung, in der mehr als eine Signaturhilfequelle verfügbar ist, wird diese Methode verwendet, um zu entscheiden, ob die Signaturhilfequelle mit der höchsten Priorität eine übereinstimmende Signatur bereitstellen kann. Wenn dies nicht der Lage ist, gibt die Methode NULL zurück, und die Quelle mit der nächstrangigsten Priorität wird aufgefordert, eine Übereinstimmung zu liefern.

    Public Function GetBestMatch(ByVal session As ISignatureHelpSession) As ISignature Implements ISignatureHelpSource.GetBestMatch
        If session.Signatures.Count > 0 Then
            Dim applicableToSpan As ITrackingSpan = session.Signatures(0).ApplicableToSpan
            Dim text As String = applicableToSpan.GetText(applicableToSpan.TextBuffer.CurrentSnapshot)
    
            If text.Trim().Equals("add") Then 'get only "add"
                Return session.Signatures(0)
            End If
        End If
        Return Nothing
    End Function
    
    public ISignature GetBestMatch(ISignatureHelpSession session)
    {
        if (session.Signatures.Count > 0)
        {
            ITrackingSpan applicableToSpan = session.Signatures[0].ApplicableToSpan;
            string text = applicableToSpan.GetText(applicableToSpan.TextBuffer.CurrentSnapshot);
    
            if (text.Trim().Equals("add"))  //get only "add" 
                return session.Signatures[0];
        }
        return null;
    }
    
  7. Implementieren Sie die Dispose() -Methode:

    Private m_isDisposed As Boolean
    
    Public Sub Dispose() Implements IDisposable.Dispose
        If Not m_isDisposed Then
            GC.SuppressFinalize(Me)
            m_isDisposed = True
        End If
    End Sub
    
    private bool m_isDisposed;
    public void Dispose()
    {
        if (!m_isDisposed)
        {
            GC.SuppressFinalize(this);
            m_isDisposed = true;
        }
    }
    

Implementieren des Signaturhilfe-Quellanbieters

Der Signaturhilfe-Quellanbieter ist für den Export des MEF-Komponententeils (Managed Extensibility Framework) und für die Instanziierung der Signaturhilfequelle verantwortlich.

So implementieren Sie den Signaturhilfe-Quellanbieter

  1. Fügen Sie eine Klasse namens TestSignatureHelpSourceProvider hinzu, die ISignatureHelpSourceProvider implementiert, und exportieren Sie sie mit einem NameAttribute , einem von ContentTypeAttribute "text" und einem OrderAttribute von Before="default".

    <Export(GetType(ISignatureHelpSourceProvider)), Name("Signature Help source"), Order(Before:="default"), ContentType("text")>
    Friend Class TestSignatureHelpSourceProvider
        Implements ISignatureHelpSourceProvider
    
    [Export(typeof(ISignatureHelpSourceProvider))]
    [Name("Signature Help source")]
    [Order(Before = "default")]
    [ContentType("text")]
    internal class TestSignatureHelpSourceProvider : ISignatureHelpSourceProvider
    
  2. Implementieren Sie TryCreateSignatureHelpSource , indem Sie instanziieren. TestSignatureHelpSource

    Public Function TryCreateSignatureHelpSource(ByVal textBuffer As ITextBuffer) As ISignatureHelpSource Implements ISignatureHelpSourceProvider.TryCreateSignatureHelpSource
        Return New TestSignatureHelpSource(textBuffer)
    End Function
    
    public ISignatureHelpSource TryCreateSignatureHelpSource(ITextBuffer textBuffer)
    {
        return new TestSignatureHelpSource(textBuffer);
    }
    

Implementieren des Befehlshandlers

Die Signaturhilfe wird in der Regel durch eine öffnende Klammer ("Zeichen und geschlossen durch eine schließende Klammer")" ausgelöst. Sie können diese Tastatureingaben behandeln, indem Sie IOleCommandTarget ausführen, sodass eine Signaturhilfesitzung ausgelöst wird, wenn ein öffnendes Klammerzeichen vor einem bekannten Methodennamen empfangen wird, und die Sitzung geschlossen wird, wenn ein schließendes Klammerzeichen empfangen wird.

So implementieren Sie den Befehlshandler

  1. Fügen Sie eine Klasse namens TestSignatureHelpCommand hinzu, die IOleCommandTarget implementiert.

    Friend NotInheritable Class TestSignatureHelpCommandHandler
        Implements IOleCommandTarget
    
    internal sealed class TestSignatureHelpCommandHandler : IOleCommandTarget
    
  2. Fügen Sie private Felder für den IVsTextView Adapter hinzu (mit denen Sie der Kette von Befehlshandlern den Befehlshandler hinzufügen können), die Textansicht, den Signaturhilfebroker und die Sitzung, eine ITextStructureNavigator und die nächste IOleCommandTarget .

    Private m_nextCommandHandler As IOleCommandTarget
    Private m_textView As ITextView
    Private m_broker As ISignatureHelpBroker
    Private m_session As ISignatureHelpSession
    Private m_navigator As ITextStructureNavigator
    
    IOleCommandTarget m_nextCommandHandler;
    ITextView m_textView;
    ISignatureHelpBroker m_broker;
    ISignatureHelpSession m_session;
    ITextStructureNavigator m_navigator;
    
  3. Fügen Sie einen Konstruktor hinzu, um diese Felder zu initialisieren und der Kette von Befehlsfiltern den Befehlsfilter hinzuzufügen.

    Friend Sub New(ByVal textViewAdapter As IVsTextView, ByVal textView As ITextView, ByVal nav As ITextStructureNavigator, ByVal broker As ISignatureHelpBroker)
        Me.m_textView = textView
        Me.m_broker = broker
        Me.m_navigator = nav
    
        'add this to the filter chain
        textViewAdapter.AddCommandFilter(Me, m_nextCommandHandler)
    End Sub
    
    internal TestSignatureHelpCommandHandler(IVsTextView textViewAdapter, ITextView textView, ITextStructureNavigator nav, ISignatureHelpBroker broker)
    {
        this.m_textView = textView;
        this.m_broker = broker;
        this.m_navigator = nav;
    
        //add this to the filter chain
        textViewAdapter.AddCommandFilter(this, out m_nextCommandHandler);
    }
    
  4. Implementieren Sie die Exec -Methode, um die Signaturhilfesitzung auszulösen, wenn der Befehlsfilter eine öffnende Klammer ("" nach einem der bekannten Methodennamen empfängt, und um die Sitzung zu schließen, wenn sie eine schließende Klammer erhält") , während die Sitzung noch aktiv ist. In jedem Fall wird der Befehl weitergeleitet.

    Public Function Exec(ByRef pguidCmdGroup As Guid, ByVal nCmdID As UInteger, ByVal nCmdexecopt As UInteger, ByVal pvaIn As IntPtr, ByVal pvaOut As IntPtr) As Integer Implements IOleCommandTarget.Exec
        Dim typedChar As Char = Char.MinValue
    
        If pguidCmdGroup = VSConstants.VSStd2K AndAlso nCmdID = CUInt(VSConstants.VSStd2KCmdID.TYPECHAR) Then
            typedChar = CChar(ChrW(CUShort(Marshal.GetObjectForNativeVariant(pvaIn))))
            If typedChar.Equals("("c) Then
                'move the point back so it's in the preceding word
                Dim point As SnapshotPoint = m_textView.Caret.Position.BufferPosition - 1
                Dim extent As TextExtent = m_navigator.GetExtentOfWord(point)
                Dim word As String = extent.Span.GetText()
                If word.Equals("add") Then
                    m_session = m_broker.TriggerSignatureHelp(m_textView)
                End If
    
            ElseIf typedChar.Equals(")"c) AndAlso m_session IsNot Nothing Then
                m_session.Dismiss()
                m_session = Nothing
            End If
        End If
        Return m_nextCommandHandler.Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut)
    End Function
    
    public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
    {
        char typedChar = char.MinValue;
    
        if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR)
        {
            typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn);
            if (typedChar.Equals('('))
            {
                //move the point back so it's in the preceding word
                SnapshotPoint point = m_textView.Caret.Position.BufferPosition - 1;
                TextExtent extent = m_navigator.GetExtentOfWord(point);
                string word = extent.Span.GetText();
                if (word.Equals("add"))
                    m_session = m_broker.TriggerSignatureHelp(m_textView);
    
            }
            else if (typedChar.Equals(')') && m_session != null)
            {
                m_session.Dismiss();
                m_session = null;
            }
        }
        return m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
    }
    
  5. Implementieren Sie die QueryStatus -Methode so, dass sie den Befehl immer weiterleitet.

    Public Function QueryStatus(ByRef pguidCmdGroup As Guid, ByVal cCmds As UInteger, ByVal prgCmds() As OLECMD, ByVal pCmdText As IntPtr) As Integer Implements IOleCommandTarget.QueryStatus
        Return m_nextCommandHandler.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText)
    End Function
    
    public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
    {
        return m_nextCommandHandler.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
    }
    

Implementieren des Signaturhilfe-Befehlsanbieters

Sie können den Signaturhilfebefehl bereitstellen, indem Sie IVsTextViewCreationListener implementieren, um den Befehlshandler zu instanziieren, wenn die Textansicht erstellt wird.

So implementieren Sie den Signaturhilfe-Befehlsanbieter

  1. Fügen Sie eine Klasse mit dem Namen TestSignatureHelpController hinzu, die IVsTextViewCreationListener implementiert, und exportieren Sie sie mit NameAttribute , ContentTypeAttribute und TextViewRoleAttribute .

    <Export(GetType(IVsTextViewCreationListener)), Name("Signature Help controller"), TextViewRole(PredefinedTextViewRoles.Editable), ContentType("text")>
    Friend Class TestSignatureHelpCommandProvider
        Implements IVsTextViewCreationListener
    
    [Export(typeof(IVsTextViewCreationListener))]
    [Name("Signature Help controller")]
    [TextViewRole(PredefinedTextViewRoles.Editable)]
    [ContentType("text")]
    internal class TestSignatureHelpCommandProvider : IVsTextViewCreationListener
    
  2. Importieren Sie IVsEditorAdaptersFactoryService (wird zum Abrufen des ITextView verwendet, wenn das -Objekt angegeben IVsTextView ist), die ITextStructureNavigatorSelectorService (zum Suchen des aktuellen Worts verwendet) und die ISignatureHelpBroker (um die Signaturhilfesitzung auszulösen).

    <Import()>
    Friend AdapterService As IVsEditorAdaptersFactoryService
    
    <Import()>
    Friend Property NavigatorService() As ITextStructureNavigatorSelectorService
    
    <Import()>
    Friend SignatureHelpBroker As ISignatureHelpBroker
    
    [Import]
    internal IVsEditorAdaptersFactoryService AdapterService;
    
    [Import]
    internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
    
    [Import]
    internal ISignatureHelpBroker SignatureHelpBroker;
    
  3. Implementieren Sie die VsTextViewCreated -Methode, indem Sie instanziieren. TestSignatureCommandHandler

    Public Sub VsTextViewCreated(ByVal textViewAdapter As IVsTextView) Implements IVsTextViewCreationListener.VsTextViewCreated
        Dim textView As ITextView = AdapterService.GetWpfTextView(textViewAdapter)
        If textView Is Nothing Then
            Return
        End If
    
        textView.Properties.GetOrCreateSingletonProperty(Function() New TestSignatureHelpCommandHandler(textViewAdapter, textView, NavigatorService.GetTextStructureNavigator(textView.TextBuffer), SignatureHelpBroker))
    End Sub
    
    public void VsTextViewCreated(IVsTextView textViewAdapter)
    {
        ITextView textView = AdapterService.GetWpfTextView(textViewAdapter);
        if (textView == null)
            return;
    
        textView.Properties.GetOrCreateSingletonProperty(
             () => new TestSignatureHelpCommandHandler(textViewAdapter,
                textView,
                NavigatorService.GetTextStructureNavigator(textView.TextBuffer),
                SignatureHelpBroker));
    }
    

Erstellen und Testen des Codes

Erstellen Sie zum Testen dieses Codes die Lösung SignatureHelpTest, und führen Sie sie in der experimentellen Instanz aus.

So erstellen und testen Sie die SignatureHelpTest-Lösung

  1. Erstellen Sie die Projektmappe.

  2. Wenn Sie dieses Projekt im Debugger ausführen, wird eine zweite Instanz von Visual Studio gestartet.

  3. Erstellen Sie eine Textdatei, und geben Sie Text ein, der das Wort "hinzufügen" sowie eine öffnende Klammer enthält.

  4. Nachdem Sie die öffnende Klammer eingegeben haben, sollte eine QuickInfo angezeigt werden, die eine Liste der beiden Signaturen für die add() Methode anzeigt.

Siehe auch