シグネチャ ヘルプ ("パラメーター ヒント" とも呼ばれます) には、ユーザーがパラメーター リストの開始文字 (通常は始めかっこ) を入力したときに、ツールヒントにメソッドのシグネチャを表示します。 パラメーターおよびパラメーターの区切り記号 (通常はコンマ) が入力されると、ツールヒントが更新され、次のパラメーターが太字で表示されます。 シグネチャ ヘルプは、次の方法で定義できます。言語サービスのコンテキストでは、独自のファイル名拡張子とコンテンツ タイプを定義し、その種類のみのシグネチャ ヘルプを表示するか、既存のコンテンツ タイプ (たとえば、"text") のシグネチャ ヘルプを表示します。 このチュートリアルでは、"text" コンテンツ タイプのシグネチャ ヘルプを表示する方法を示します。
シグネチャ ヘルプは、通常、"(" (始めかっこ) などの特定の文字を入力するとトリガーされ、")" (終わりかっこ) などの別の文字を入力すると破棄されます。 文字を入力するとトリガーされる IntelliSense 機能は、キーストローク (IOleCommandTarget インターフェイス) のコマンド ハンドラーと、IVsTextViewCreationListener インターフェイスを実装するハンドラー プロバイダーを使用して実装できます。 シグネチャ ヘルプに参加するシグネチャの一覧であるシグネチャ ヘルプ ソースを作成するには、ISignatureHelpSource インターフェイスと、ISignatureHelpSourceProvider インターフェイスを実行するソース プロバイダーを実装します。 プロバイダーは、Managed Extensibility Framework (MEF) コンポーネント パーツであり、ソースとコントローラーのクラスをエクスポートしたり、テキスト バッファー内を移動できるようにする ITextStructureNavigatorSelectorService や、シグネチャ ヘルプ セッションをトリガーする ISignatureHelpBroker などのサービスやブローカーをインポートしたりする役割を担います。
このチュートリアルでは、ハードコーディングされた識別子のセットに対してシグネチャ ヘルプをセットアップする方法を示します。 完全な実装では、言語がそのコンテンツを提供する役割を担います。
MEF プロジェクトの作成
MEF プロジェクトを作成するには
C# VSIX プロジェクトを作成します。 ([新しいプロジェクト] ダイアログで、[Visual C#]、[拡張機能]、[VSIX プロジェクト] の順に選択します。) ソリューションに SignatureHelpTest
という名前を付けます。
プロジェクトに、[エディター分類子] 項目テンプレートを追加します。 詳細については、「エディター項目テンプレートを使用して拡張機能を作成する」を参照してください。
既存のクラス ファイルを削除します。
次の参照をプロジェクトに追加し、CopyLocal が false
に設定されていることを確認します。
Microsoft.VisualStudio.Editor
Microsoft.VisualStudio.Language.Intellisense
Microsoft.VisualStudio.OLE.Interop
Microsoft.VisualStudio.Shell.14.0
Microsoft.VisualStudio.TextManager.Interop
シグネチャ ヘルプのシグネチャとパラメーターを実装する
シグネチャ ヘルプ ソースは、ISignature を実装するシグネチャに基づいています。そのシグネチャそれぞれには、IParameter を実装するパラメーターが含まれています。 完全な実装では、この情報は言語ドキュメントから取得されますが、この例では、シグネチャはハードコーディングされています。
シグネチャ ヘルプのシグネチャとパラメーターを実装するには
クラス ファイルを追加し、その名前を SignatureHelpSource
にします。
次のインポートを追加します。
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;
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
IParameter を実装する、TestParameter
という名前のクラスを追加します。
internal class TestParameter : IParameter
Friend Class TestParameter
Implements IParameter
すべてのプロパティを設定するコンストラクターを追加します。
public TestParameter(string documentation, Span locus, string name, ISignature signature)
{
Documentation = documentation;
Locus = locus;
Name = name;
Signature = signature;
}
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
IParameter のプロパティを追加します。
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; }
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
ISignature を実装する、TestSignature
という名前のクラスを追加します。
internal class TestSignature : ISignature
Friend Class TestSignature
Implements ISignature
いくつかのプライベート フィールドを追加します。
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;
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
フィールドを設定し、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);
}
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
CurrentParameterChanged
イベントを宣言します。 このイベントは、ユーザーがシグネチャのいずれかのパラメーターを入力したときに発生します。
public event EventHandler<CurrentParameterChangedEventArgs> CurrentParameterChanged;
Public Event CurrentParameterChanged As EventHandler(Of CurrentParameterChangedEventArgs) Implements ISignature.CurrentParameterChanged
プロパティ値が変更されたときに CurrentParameterChanged
イベントが発生するように、CurrentParameter プロパティを実装します。
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);
}
}
}
ReadOnly Property CurrentParameter() As IParameter Implements ISignature.CurrentParameter
Get
Return m_currentParameter
End Get
End Property
CurrentParameterChanged
イベントを発生させるメソッドを追加します。
private void RaiseCurrentParameterChanged(IParameter prevCurrentParameter, IParameter newCurrentParameter)
{
EventHandler<CurrentParameterChangedEventArgs> tempHandler = this.CurrentParameterChanged;
if (tempHandler != null)
{
tempHandler(this, new CurrentParameterChangedEventArgs(prevCurrentParameter, newCurrentParameter));
}
}
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
ApplicableToSpan におけるコンマの数とシグネチャ内のコンマの数を比較して、現在のパラメーターを計算するメソッドを追加します。
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];
}
}
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
ComputeCurrentParameter()
メソッドを呼び出す Changed イベントのイベント ハンドラーを追加します。
internal void OnSubjectBufferChanged(object sender, TextContentChangedEventArgs e)
{
this.ComputeCurrentParameter();
}
Friend Sub OnSubjectBufferChanged(ByVal sender As Object, ByVal e As TextContentChangedEventArgs)
Me.ComputeCurrentParameter()
End Sub
ApplicableToSpan プロパティを実装します。 このプロパティは、シグネチャが適用されるバッファー内のテキストの範囲に対応する ITrackingSpan を保持します。
public ITrackingSpan ApplicableToSpan
{
get { return (m_applicableToSpan); }
internal set { m_applicableToSpan = value; }
}
ReadOnly Property ApplicableToSpan() As ITrackingSpan Implements ISignature.ApplicableToSpan
Get
Return (m_applicableToSpan)
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; }
}
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
シグネチャ ヘルプ ソースを実装する
シグネチャ ヘルプ ソースは、情報の提供先の一連のシグネチャです。
シグネチャ ヘルプ ソースを実装するには
ISignatureHelpSource を実装する、TestSignatureHelpSource
という名前のクラスを追加します。
internal class TestSignatureHelpSource : ISignatureHelpSource
Friend Class TestSignatureHelpSource
Implements ISignatureHelpSource
テキスト バッファーに参照を追加します。
private ITextBuffer m_textBuffer;
Private m_textBuffer As ITextBuffer
テキスト バッファーとシグネチャ ヘルプ ソース プロバイダーを設定するコンストラクターを追加します。
public TestSignatureHelpSource(ITextBuffer textBuffer)
{
m_textBuffer = textBuffer;
}
Public Sub New(ByVal textBuffer As ITextBuffer)
m_textBuffer = textBuffer
End Sub
AugmentSignatureHelpSession メソッドを実装します。 この例では、シグネチャがハードコーディングされていますが、完全な実装では、言語ドキュメントからこの情報を取得します。
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));
}
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
ヘルパー メソッド CreateSignature()
は、例を示す目的でのみ用意されています。
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;
}
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
GetBestMatch メソッドを実装します。 この例では、2 つのシグネチャとそのそれぞれに 2 つのパラメーターがあります。 したがって、このメソッドは必要ありません。 複数のシグネチャ ヘルプ ソースを使用できる完全な実装では、このメソッドは、優先度が最も高いシグネチャ ヘルプ ソースで、一致するシグネチャを提供できるかどうかを判断するために使用されます。 できない場合は、メソッドから null が返され、次に高い優先度のソースが一致を提供するように求められます。
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;
}
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
Dispose()
メソッドを実装します。
private bool m_isDisposed;
public void Dispose()
{
if (!m_isDisposed)
{
GC.SuppressFinalize(this);
m_isDisposed = true;
}
}
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
シグネチャ ヘルプ ソース プロバイダーを実装する
シグネチャ ヘルプ ソース プロバイダーは、Managed Extensibility Framework (MEF) コンポーネント パーツのエクスポートと、シグネチャ ヘルプ ソースのインスタンス化を担当します。
シグネチャ ヘルプ ソース プロバイダーを実装するには
ISignatureHelpSourceProvider を実装する、TestSignatureHelpSourceProvider
という名前のクラスを追加し、NameAttribute、ContentTypeAttribute として "text"、OrderAttribute として Before="default" を使用してこれをエクスポートします。
[Export(typeof(ISignatureHelpSourceProvider))]
[Name("Signature Help source")]
[Order(Before = "default")]
[ContentType("text")]
internal class TestSignatureHelpSourceProvider : ISignatureHelpSourceProvider
<Export(GetType(ISignatureHelpSourceProvider)), Name("Signature Help source"), Order(Before:="default"), ContentType("text")>
Friend Class TestSignatureHelpSourceProvider
Implements ISignatureHelpSourceProvider
TestSignatureHelpSource
をインスタンス化して TryCreateSignatureHelpSource を実装します。
public ISignatureHelpSource TryCreateSignatureHelpSource(ITextBuffer textBuffer)
{
return new TestSignatureHelpSource(textBuffer);
}
Public Function TryCreateSignatureHelpSource(ByVal textBuffer As ITextBuffer) As ISignatureHelpSource Implements ISignatureHelpSourceProvider.TryCreateSignatureHelpSource
Return New TestSignatureHelpSource(textBuffer)
End Function
コマンド ハンドラーを実装する
シグネチャ ヘルプは、通常、始めかっこ "(" 文字でトリガーされ、終わりかっこ ")" 文字で終了します。 IOleCommandTarget を実行して、既知のメソッド名が前に置かれた始めかっこ文字を受け取ったときにシグネチャ ヘルプ セッションをトリガーし、終わりかっこ文字を受け取ったときにセッションを破棄することで、これらのキーストロークを処理できます。
コマンド ハンドラーを実装するには
IOleCommandTarget を実装する、TestSignatureHelpCommand
という名前のクラスを追加します。
internal sealed class TestSignatureHelpCommandHandler : IOleCommandTarget
Friend NotInheritable Class TestSignatureHelpCommandHandler
Implements IOleCommandTarget
IVsTextView アダプター (コマンド ハンドラーのチェーンにコマンド ハンドラーを追加できるようにします)、テキスト ビュー、シグネチャ ヘルプ ブローカーおよびセッション、ITextStructureNavigator、次の IOleCommandTarget のプライベート フィールドを追加します。
IOleCommandTarget m_nextCommandHandler;
ITextView m_textView;
ISignatureHelpBroker m_broker;
ISignatureHelpSession m_session;
ITextStructureNavigator m_navigator;
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
これらのフィールドを初期化し、コマンド フィルターをコマンド フィルターのチェーンに追加するためにコンストラクターを追加します。
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);
}
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
既知のいずれかのメソッド名の後でコマンド フィルターが始めかっこ "(" 文字を受け取ると、シグネチャ ヘルプ セッションをトリガーし、セッションがまだアクティブな間に終わりかっこ ")" 文字を受け取ると、セッションを破棄するように Exec メソッドを実装します。 いずれの場合も、コマンドは転送されます。
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);
}
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
QueryStatus メソッドを実装して、常にコマンドを転送するようにします。
public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
{
return m_nextCommandHandler.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
}
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
シグネチャ ヘルプ コマンド プロバイダーを実装する
テキスト ビューが作成されるときに、IVsTextViewCreationListener を実装してコマンド ハンドラーをインスタンス化すると、シグネチャ ヘルプ コマンドを提供できます。
シグネチャ ヘルプ コマンド プロバイダーを実装するには
IVsTextViewCreationListener を実装する、TestSignatureHelpController
という名前のクラスを追加し、NameAttribute、ContentTypeAttribute、TextViewRoleAttribute を使用してエクスポートします。
[Export(typeof(IVsTextViewCreationListener))]
[Name("Signature Help controller")]
[TextViewRole(PredefinedTextViewRoles.Editable)]
[ContentType("text")]
internal class TestSignatureHelpCommandProvider : IVsTextViewCreationListener
<Export(GetType(IVsTextViewCreationListener)), Name("Signature Help controller"), TextViewRole(PredefinedTextViewRoles.Editable), ContentType("text")>
Friend Class TestSignatureHelpCommandProvider
Implements IVsTextViewCreationListener
(ITextView を取得するために使用され、IVsTextView オブジェクトが与えられる) IVsEditorAdaptersFactoryService、(現在の単語を検索するために使用される) ITextStructureNavigatorSelectorService、(シグネチャ ヘルプ セッションをトリガーする) ISignatureHelpBroker をインポートします。
[Import]
internal IVsEditorAdaptersFactoryService AdapterService;
[Import]
internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
[Import]
internal ISignatureHelpBroker SignatureHelpBroker;
<Import()>
Friend AdapterService As IVsEditorAdaptersFactoryService
<Import()>
Friend Property NavigatorService() As ITextStructureNavigatorSelectorService
<Import()>
Friend SignatureHelpBroker As ISignatureHelpBroker
TestSignatureCommandHandler
をインスタンス化することで VsTextViewCreated メソッドを実装します。
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));
}
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
コードをビルドしてテストする
このコードをテストするには、SignatureHelpTest ソリューションをビルドして、実験用インスタンスで実行します。
SignatureHelpTest ソリューションをビルドしテストするには
ソリューションをビルドします。
デバッガーでこのプロジェクトを実行すると、Visual Studio の 2 つ目のインスタンスが起動されます。
テキスト ファイルを作成し、"add" という単語と始めかっこを含むテキストを入力します。
始めかっこを入力した後、add()
メソッドの 2 つのシグネチャの一覧を示すツールヒントが表示されます。
関連するコンテンツ