Procedura dettagliata: Visualizzare la Guida alla firma
La Guida alla firma (nota anche come Informazioni parametro) visualizza la firma di un metodo in una descrizione comando quando un utente digita il carattere iniziale dell'elenco di parametri (in genere una parentesi di apertura). Come parametro e separatore di parametri (in genere una virgola) vengono digitati, la descrizione comando viene aggiornata per visualizzare il parametro successivo in grassetto. È possibile definire la Guida per le firme nei modi seguenti: nel contesto di un servizio linguistico, definire l'estensione del nome file e il tipo di contenuto e visualizzare la Guida per la firma solo per quel tipo o visualizzare la Guida della firma per un tipo di contenuto esistente ,ad esempio "text". Questa procedura dettagliata illustra come visualizzare la Guida della firma per il tipo di contenuto "text".
La Guida della firma viene in genere attivata digitando un carattere specifico, ad esempio "(" (parentesi di apertura) e ignorato digitando un altro carattere, ad esempio ")" (parentesi di chiusura). Le funzionalità di IntelliSense attivate digitando un carattere possono essere implementate usando un gestore comandi per le sequenze di tasti (l'interfaccia IOleCommandTarget ) e un provider di gestori che implementa l'interfaccia IVsTextViewCreationListener . Per creare l'origine della Guida della firma, ovvero l'elenco delle firme che partecipano alla Guida della firma, implementare l'interfaccia ISignatureHelpSource e un provider di origine che esegue l'interfaccia ISignatureHelpSourceProvider . I provider sono parti del componente MEF (Managed Extensibility Framework) e sono responsabili dell'esportazione delle classi di origine e controller e dell'importazione di servizi e broker, ad esempio , ITextStructureNavigatorSelectorServiceche consente di spostarsi nel buffer di testo e , ISignatureHelpBrokerche attiva la sessione della Guida della Firma.
Questa procedura dettagliata illustra come configurare la Guida della firma per un set di identificatori hardcoded. Nelle implementazioni complete, il linguaggio è responsabile della fornitura di tale contenuto.
Creazione di un progetto MEF
Per creare un progetto MEF
Creare un progetto VSIX C#. (In Finestra di dialogo Nuovo progetto , selezionare Visual C# / Estendibilità e quindi progetto VSIX. Assegnare alla soluzione
SignatureHelpTest
il nome .Aggiungere un modello di elemento classificatore dell'editor al progetto. Per altre informazioni, vedere Creare un'estensione con un modello di elemento dell'editor.
Eliminare i file di classe esistenti.
Aggiungere i riferimenti seguenti al progetto e assicurarsi che CopyLocal sia impostato su
false
:Microsoft.VisualStudio.Editor
Microsoft.VisualStudio.Language.Intellisense
Microsoft.VisualStudio.OLE.Interop
Microsoft.VisualStudio.Shell.14.0
Microsoft.VisualStudio.TextManager.Interop
Implementare firme e parametri della Guida per la firma
L'origine della Guida della firma si basa sulle firme che implementano ISignature, ognuna delle quali contiene parametri che implementano IParameter. In un'implementazione completa queste informazioni vengono ottenute dalla documentazione del linguaggio, ma in questo esempio le firme sono hardcoded.
Per implementare le firme e i parametri della Guida per la firma
Aggiungere un file di classe e assegnargli il nome
SignatureHelpSource
.Aggiungere le importazioni seguenti.
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;
Aggiungere una classe denominata
TestParameter
che implementa IParameter.Aggiungere un costruttore che imposta tutte le proprietà.
Aggiungere le proprietà di IParameter.
Aggiungere una classe denominata
TestSignature
che implementa ISignature.Aggiungere alcuni campi privati.
Aggiungere un costruttore che imposta i campi e sottoscrive l'evento Changed .
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); }
Dichiarare un
CurrentParameterChanged
evento. Questo evento viene generato quando l'utente compila uno dei parametri nella firma.Implementare la CurrentParameter proprietà in modo che generi l'evento
CurrentParameterChanged
quando viene modificato il valore della proprietà.Aggiungere un metodo che genera l'evento
CurrentParameterChanged
.private void RaiseCurrentParameterChanged(IParameter prevCurrentParameter, IParameter newCurrentParameter) { EventHandler<CurrentParameterChangedEventArgs> tempHandler = this.CurrentParameterChanged; if (tempHandler != null) { tempHandler(this, new CurrentParameterChangedEventArgs(prevCurrentParameter, newCurrentParameter)); } }
Aggiungere un metodo che calcola il parametro corrente confrontando il numero di virgole nell'oggetto ApplicableToSpan con il numero di virgole nella firma.
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]; } }
Aggiungere un gestore eventi per l'evento Changed che chiama il
ComputeCurrentParameter()
metodo .Implementare la proprietà ApplicableToSpan. Questa proprietà contiene un oggetto ITrackingSpan che corrisponde all'intervallo di testo nel buffer a cui si applica la firma.
Implementare gli altri parametri.
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; } }
Implementare l'origine della Guida per la firma
L'origine della Guida della firma è il set di firme per cui si forniscono informazioni.
Per implementare l'origine della Guida della firma
Aggiungere una classe denominata
TestSignatureHelpSource
che implementa ISignatureHelpSource.Aggiungere un riferimento al buffer di testo.
Aggiungere un costruttore che imposta il buffer di testo e il provider di origine della Guida della firma.
Implementa il metodo AugmentSignatureHelpSession. In questo esempio le firme sono hardcoded, ma in un'implementazione completa si otterrebbero queste informazioni dalla documentazione del linguaggio.
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)); }
Il metodo
CreateSignature()
helper viene fornito solo per l'illustrazione.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; }
Implementa il metodo GetBestMatch. In questo esempio sono presenti solo due firme, ognuna delle quali ha due parametri. Pertanto, questo metodo non è obbligatorio. In un'implementazione più completa, in cui è disponibile più di un'origine della Guida di firma, questo metodo viene usato per decidere se l'origine della Guida con la firma con priorità più alta può fornire una firma corrispondente. In caso contrario, il metodo restituisce Null e all'origine con priorità più alta successiva viene chiesto di fornire una corrispondenza.
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; }
Implementare il
Dispose()
metodo :
Implementare il provider di origine della Guida per la firma
Il provider di origine della Guida per le firme è responsabile dell'esportazione della parte del componente MEF (Managed Extensibility Framework) e della creazione di un'istanza dell'origine della Guida della firma.
Per implementare il provider di origine della Guida della firma
Aggiungere una classe denominata
TestSignatureHelpSourceProvider
che implementa ISignatureHelpSourceProvidered esportarla con , NameAttributeun ContentTypeAttribute valore di "text" e un OrderAttribute valore before="default".Implementare TryCreateSignatureHelpSource creando un'istanza di
TestSignatureHelpSource
.
Implementare il gestore dei comandi
La Guida della firma viene in genere attivata da una parentesi di apertura "(" carattere e ignorata da una parentesi chiusa ")". È possibile gestire queste sequenze di tasti eseguendo un oggetto IOleCommandTarget in modo che attivi una sessione della Guida della Firma quando riceve una parentesi di apertura preceduta da un nome di metodo noto e chiude la sessione quando riceve una parentesi di chiusura.
Per implementare il gestore dei comandi
Aggiungere una classe denominata
TestSignatureHelpCommand
che implementa IOleCommandTarget.Aggiungere campi privati per l'adapter IVsTextView (che consente di aggiungere il gestore di comandi alla catena di gestori di comandi), la visualizzazione testo, il gestore della Guida della firma e la sessione, un ITextStructureNavigatore il successivo IOleCommandTarget.
Aggiungere un costruttore per inizializzare questi campi e aggiungere il filtro dei comandi alla catena di filtri dei comandi.
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); }
Implementare il Exec metodo per attivare la sessione della Guida della firma quando il filtro dei comandi riceve una parentesi di apertura "(" carattere dopo uno dei nomi di metodi noti e per ignorare la sessione quando riceve una parentesi di chiusura ")" mentre la sessione è ancora attiva. In ogni caso, il comando viene inoltrato.
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); }
Implementare il QueryStatus metodo in modo che inoltra sempre il comando .
Implementare il provider di comandi della Guida per la firma
È possibile fornire il comando Della Guida per la firma implementando per creare un'istanza IVsTextViewCreationListener del gestore dei comandi quando viene creata la visualizzazione testo.
Per implementare il provider di comandi della Guida per la firma
Aggiungere una classe denominata
TestSignatureHelpController
che implementa IVsTextViewCreationListener ed esportarla con NameAttribute, ContentTypeAttributee TextViewRoleAttribute.IVsEditorAdaptersFactoryService Importare (usato per ottenere , ITextViewdato l'oggetto IVsTextView ), il ITextStructureNavigatorSelectorService (usato per trovare la parola corrente) e il ISignatureHelpBroker (per attivare la sessione della Guida della firma).
Implementare il VsTextViewCreated metodo creando un'istanza di
TestSignatureCommandHandler
.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)); }
Compilare e testare il codice
Per testare questo codice, compilare la soluzione SignatureHelpTest ed eseguirla nell'istanza sperimentale.
Per compilare e testare la soluzione SignatureHelpTest
Compilare la soluzione.
Quando si esegue questo progetto nel debugger, viene avviata una seconda istanza di Visual Studio.
Creare un file di testo e digitare un testo che includa la parola "add" e una parentesi di apertura.
Dopo aver digitato la parentesi di apertura, verrà visualizzata una descrizione comando che visualizza un elenco delle due firme per il
add()
metodo .