在编辑器扩展中创建代码段并将它们包括,以便该扩展的用户可以将它们添加到代码。
代码段是文件可以包含代码或其他文本片段。 若要查看注册特定编程语言,在 工具 菜单的所有代码段,单击 代码段管理器。 插入代码段在要该代码段,单击 插入代码段 或 外侧的文件,右击,查找所需的代码段,然后双击它。 按 tab 或 SHIFT+TAB 修改代码段的相关部分然后按以下内容或 ESC 接受。 有关更多信息,请参见代码段。
代码段在名为 .snippet 文件扩展名的 XML 文件中。 代码段可以包含显示的字段,在插入后此代码段,以便用户可以查找和更改它们。 代码段文件。 代码段管理器 还提供信息,以便可以显示在正确的类别的代码段名称。 有关代码段架构的信息,请参见 代码段架构参考。
此演练演示如何完成以下任务:
创建和特定语言的注册代码段。
添加 插入代码段 命令添加到快捷菜单。
实现代码段展开。
本演练基于 演练:显示的语句完成。
系统必备
若要完成本演练,您必须安装 Visual Studio 2010 SDK。 有关 Visual Studio SDK 的信息以及下载它,请 Visual Studio 扩展性开发人员中心) 参见 MSDN 网站上。
创建和注册代码段
通常,代码段与注册的语言服务。 但是,您不必实现 LanguageService 注册代码段。 相反,请指定 GUID 代码段中索引文件中使用相同的 GUID 在您添加到项目的 ProvideLanguageCodeExpansionAttribute 。
下列步骤演示如何创建代码段和使它们与特定的 GUID。
创建代码段
创建以下目录结构:
%InstallDir% \ TestSnippets \ snippets \ 1033 \
其中 %InstallDir% 是 Visual Studio 安装文件夹。 (尽管此路径通常用于安装代码段,可以指定任意路径。)
在 \ 1033 \ 文件夹中,创建一个 .xml 文件并将其命名为 SnippetIndex.xml。 (尽管此名称为代码段索引文件通常使用,可以指定任何名称,只要它具有一个 .xml 文件扩展名。)添加以下文本,然后删除占位符 GUID 并向。
<?xml version="1.0" encoding="utf-8" ?> <SnippetCollection> <Language Lang="TestSnippets" Guid="{00000000-0000-0000-0000-000000000000}"> <SnippetDir> <OnOff>On</OnOff> <Installed>true</Installed> <Locale>1033</Locale> <DirPath>%InstallRoot%\TestSnippets\Snippets\%LCID%\</DirPath> <LocalizedName>Snippets</LocalizedName> </SnippetDir> </Language> </SnippetCollection>
创建一个文件在代码段文件夹,将其命名为测试.snippet,然后添加以下文本:
<?xml version="1.0" encoding="utf-8" ?> <CodeSnippets xmlns="https://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> <CodeSnippet Format="1.0.0"> <Header> <Title>Test replacement fields</Title> <Shortcut>test</Shortcut> <Description>Code snippet for testing replacement fields</Description> <Author>MSIT</Author> <SnippetTypes> <SnippetType>Expansion</SnippetType> </SnippetTypes> </Header> <Snippet> <Declarations> <Literal> <ID>param1</ID> <ToolTip>First field</ToolTip> <Default>first</Default> </Literal> <Literal> <ID>param2</ID> <ToolTip>Second field</ToolTip> <Default>second</Default> </Literal> </Declarations> <References> <Reference> <Assembly>System.Windows.Forms.dll</Assembly> </Reference> </References> <Code Language="TestSnippets"> <![CDATA[MessageBox.Show("$param1$"); MessageBox.Show("$param2$");]]> </Code> </Snippet> </CodeSnippet> </CodeSnippets>
以下步骤演示如何注册代码段。
对于给定的 GUID 的注册代码段
打开 CompletionTest 项目。 有关如何创建此项目的信息,请参见 演练:显示的语句完成。
在项目中,添加对以下程序集的引用:
Microsoft.VisualStudio.TextManager.Interop
Microsoft.VisualStudio.TextManager.Interop.8.0
microsoft.msxml
注册代码段,该项目必须输出 .pkgdef 文件。 有关更多信息,请参见 Registering VSPackages。
在项目中,打开 source.extension.vsixmanifest 文件。
在 内容 部分中,单击 添加内容,选择 使用包 内容类型,选择 项目 选项,并且,在中选择 TestCompletion 下拉列表。
以下行应出现在文件:
TestCompletion;PkgdefProjectOutputGroup|
保存 source.extension.vsixmanifest 文件并将其关闭。
添加静态 SnippetUtilities 类添加到项目。
Module SnippetUtilities
static class SnippetUtilities
在 SnippetUtilities 类中,定义 GUID 并为其指定所在 SnippetsIndex.xml 文件使用的值。
Friend Const LanguageServiceGuidStr As String = "00000000-0000-0000-0000-00000000"
internal const string LanguageServiceGuidStr = "00000000-0000-0000-0000-00000000";
添加 ProvideLanguageCodeExpansionAttribute 到 TestCompletionHandler 类。 此属性可添加到任何公共或内部 (非静态) 类在项目。 (您可能必须添加 Microsoft.VisualStudio.Shell 命名空间 using 语句)。
<ProvideLanguageCodeExpansion( SnippetUtilities.LanguageServiceGuidStr, "TestSnippets", 0, "TestSnippets", "%InstallRoot%\TestSnippets\Snippets\%LCID%\SnippetsIndex.xml", SearchPaths:="%InstallRoot%\TestSnippets\Snippets\%LCID%\", ForceCreateDirs:="%InstallRoot%\TestSnippets\Snippets\%LCID%\")> Friend Class TestCompletionCommandHandler Implements IOleCommandTarget
[ProvideLanguageCodeExpansion( SnippetUtilities.LanguageServiceGuidStr, "TestSnippets", //the language name 0, //the resource id of the language "TestSnippets", //the language ID used in the .snippet files @"%InstallRoot%\TestSnippets\Snippets\%LCID%\SnippetsIndex.xml", //the path of the index file SearchPaths = @"%InstallRoot%\TestSnippets\Snippets\%LCID%\", ForceCreateDirs = @"%InstallRoot%\TestSnippets\Snippets\%LCID%\")] internal class TestCompletionCommandHandler : IOleCommandTarget
生成并运行该项目。 在启动 Visual Studio 的实验实例中,在运行项目时,所签入的代码段在 TestSnippets 语言下的 代码段管理器 应显示。
添加用于插入代码段命令添加到快捷菜单
插入代码段 命令不包括在文本文件的快捷菜单。 因此,必须启用命令。
若要添加插入代码段 " 命令到快捷菜单
打开 TestCompletionCommandHandler 类文件。
因为此类实现 IOleCommandTarget,可以激活在 QueryStatus 方法的 插入代码段 命令。 在启用命令之前,请检查不会调用此方法在自动化功能中,这是因为,如果 插入代码段 命令单击时,它将显示代码段选择器用户界面 (UI)。
Public Function QueryStatus(ByRef pguidCmdGroup As Guid, ByVal cCmds As UInteger, ByVal prgCmds As OLECMD(), ByVal pCmdText As IntPtr) As Integer Implements IOleCommandTarget.QueryStatus If Not VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider) Then If pguidCmdGroup = VSConstants.VSStd2K AndAlso cCmds > 0 Then ' make the Insert Snippet command appear on the context menu If CUInt(prgCmds(0).cmdID) = CUInt(VSConstants.VSStd2KCmdID.INSERTSNIPPET) Then prgCmds(0).cmdf = CInt(Constants.MSOCMDF_ENABLED) Or CInt(Constants.MSOCMDF_SUPPORTED) Return VSConstants.S_OK End If End If End If Return m_nextCommandHandler.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText) End Function
public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) { if (!VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider)) { if (pguidCmdGroup == VSConstants.VSStd2K && cCmds > 0) { // make the Insert Snippet command appear on the context menu if ((uint)prgCmds[0].cmdID == (uint)VSConstants.VSStd2KCmdID.INSERTSNIPPET) { prgCmds[0].cmdf = (int)Constants.MSOCMDF_ENABLED | (int)Constants.MSOCMDF_SUPPORTED; return VSConstants.S_OK; } } } return m_nextCommandHandler.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); }
生成并运行该项目。 在的实验实例中,打开具有 .zzz 文件扩展名的文件然后右击任意位置。它。 插入代码段 命令应显示在快捷菜单上。
实现在代码段选择器 UI 的代码段展开
本节演示如何实现代码段扩展,以便代码段选择器 UI,将突出显示 插入代码段 在快捷菜单中单击。 代码段也会扩展,当用户键入代码段的快捷方式然后按 tab。
若要显示代码段选择器 UI 和进行导航和之后插入代码段接受,请使用 Exec 方法。 插入用 OnItemChosen 方法处理。
代码段扩展的实现使用传统 Microsoft.VisualStudio.TextManager.Interop 接口。 当从一个当前编辑时强制转换为类对于旧式代码,应记住旧接口在文本缓冲区使用行号和列号的组合指定位置,但是,当前类使用一个索引。 因此,因此,如果缓冲区具有三行的每个有字符 (以及换行符,计数为 1 个字符),第三行的第四字符在当前实现的位置 27,但是,它位于第 2 行,要在早期实现的位置 3。
实现外接代码段
为包含 TestCompletionCommandHandler 类的文件中,添加以下 using 语句。
Imports Microsoft.VisualStudio.Text.Operations Imports MSXML
using Microsoft.VisualStudio.Text.Operations; using MSXML; using System.ComponentModel.Composition;
使 TestCompletionCommandHandler 类实现 IVsExpansionClient 接口。
<ProvideLanguageCodeExpansion( SnippetUtilities.LanguageServiceGuidStr, "TestSnippets", 0, "TestSnippets", "%InstallRoot%\TestSnippets\Snippets\%LCID%\SnippetsIndex.xml", SearchPaths:="%InstallRoot%\TestSnippets\Snippets\%LCID%\", ForceCreateDirs:="%InstallRoot%\TestSnippets\Snippets\%LCID%\")> Friend Class TestCompletionCommandHandler Implements IOleCommandTarget Implements IVsExpansionClient
internal class TestCompletionCommandHandler : IOleCommandTarget, IVsExpansionClient
在 TestCompletionCommandHandlerProvider 类,请导入 ITextStructureNavigatorSelectorService。
<Import()> Friend Property NavigatorService As ITextStructureNavigatorSelectorService
[Import] internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
添加代码展开接口和 IVsTextView的某些私有字段。
Dim m_vsTextView As IVsTextView Dim m_exManager As IVsExpansionManager Dim m_exSession As IVsExpansionSession
IVsTextView m_vsTextView; IVsExpansionManager m_exManager; IVsExpansionSession m_exSession;
在 TestCompletionCommandHandler 类的构造函数中,设置以下字段。
Friend Sub New(ByVal textViewAdapter As IVsTextView, ByVal textView As ITextView, ByVal provider As TestCompletionHandlerProvider) Me.m_textView = textView Me.m_provider = provider Me.m_vsTextView = textViewAdapter Dim textManager As IVsTextManager2 = DirectCast(m_provider.ServiceProvider.GetService(GetType(SVsTextManager)), IVsTextManager2) textManager.GetExpansionManager(m_exManager) m_exSession = Nothing 'add the command to the command chain textViewAdapter.AddCommandFilter(Me, m_nextCommandHandler) End Sub
internal TestCompletionCommandHandler(IVsTextView textViewAdapter, ITextView textView, TestCompletionHandlerProvider provider) { this.m_textView = textView; m_vsTextView = textViewAdapter; m_provider = provider; //get the text manager from the service provider IVsTextManager2 textManager = (IVsTextManager2)m_provider.ServiceProvider.GetService(typeof(SVsTextManager)); textManager.GetExpansionManager(out m_exManager); m_exSession = null; //add the command to the command chain textViewAdapter.AddCommandFilter(this, out m_nextCommandHandler); }
若要显示代码段选择器,当用户单击 插入代码段 命令时,将以下代码添加到 Exec 方法。 (使此声明的可读性,请为语句完成使用的可执行 () 代码不显示;相反,代码块添加到现有的方法。)添加以下代码块在检查字符的代码后面。
'code previously written for Exec If pguidCmdGroup = VSConstants.VSStd2K AndAlso nCmdID = CUInt(VSConstants.VSStd2KCmdID.TYPECHAR) Then typedChar = ChrW(CUShort(Marshal.GetObjectForNativeVariant(pvaIn))) End If 'the snippet picker code starts here If nCmdID = CUInt(VSConstants.VSStd2KCmdID.INSERTSNIPPET) Then Dim textManager As IVsTextManager2 = DirectCast(m_provider.ServiceProvider.GetService(GetType(SVsTextManager)), IVsTextManager2) textManager.GetExpansionManager(m_exManager) m_exManager.InvokeInsertionUI( m_vsTextView, Me, New Guid(SnippetUtilities.LanguageServiceGuidStr), Nothing, 0, 0, Nothing, 0, 0, "TestSnippets", String.Empty) Return VSConstants.S_OK End If
//code previously written for Exec if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR) { typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); } //the snippet picker code starts here if (nCmdID == (uint)VSConstants.VSStd2KCmdID.INSERTSNIPPET) { IVsTextManager2 textManager = (IVsTextManager2)m_provider.ServiceProvider.GetService(typeof(SVsTextManager)); textManager.GetExpansionManager(out m_exManager); m_exManager.InvokeInsertionUI( m_vsTextView, this, //the expansion client new Guid(SnippetUtilities.LanguageServiceGuidStr), null, //use all snippet types 0, //number of types (0 for all) 0, //ignored if iCountTypes == 0 null, //use all snippet kinds 0, //use all snippet kinds 0, //ignored if iCountTypes == 0 "TestSnippets", //the text to show in the prompt string.Empty); //only the ENTER key causes insert return VSConstants.S_OK; }
如果代码段都有可导航的字段,展开会话时保持打开,直到展开显式接受;如果该代码段具有不同的字段,则该会话关闭并返回作为 null 用 InvokeInsertionUI 方法。 在 Exec 方法,在上一步添加的代码段选择器 UI 代码后面,添加下列代码以处理代码段导航 (当用户在插入代码段后按 tab 或 SHIFT+TAB 时)。
'the expansion insertion is handled in OnItemChosen 'if the expansion session is still active, handle tab/backtab/return/cancel If m_exSession IsNot Nothing Then If nCmdID = CUInt(VSConstants.VSStd2KCmdID.BACKTAB) Then m_exSession.GoToPreviousExpansionField() Return VSConstants.S_OK ElseIf nCmdID = CUInt(VSConstants.VSStd2KCmdID.TAB) Then m_exSession.GoToNextExpansionField(0) 'false to support cycling through all the fields Return VSConstants.S_OK ElseIf nCmdID = CUInt(VSConstants.VSStd2KCmdID.[RETURN]) OrElse nCmdID = CUInt(VSConstants.VSStd2KCmdID.CANCEL) Then If m_exSession.EndCurrentExpansion(0) = VSConstants.S_OK Then m_exSession = Nothing Return VSConstants.S_OK End If End If End If
//the expansion insertion is handled in OnItemChosen //if the expansion session is still active, handle tab/backtab/return/cancel if (m_exSession != null) { if (nCmdID == (uint)VSConstants.VSStd2KCmdID.BACKTAB) { m_exSession.GoToPreviousExpansionField(); return VSConstants.S_OK; } else if (nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB) { m_exSession.GoToNextExpansionField(0); //false to support cycling through all the fields return VSConstants.S_OK; } else if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN || nCmdID == (uint)VSConstants.VSStd2KCmdID.CANCEL) { if (m_exSession.EndCurrentExpansion(0) == VSConstants.S_OK) { m_exSession = null; return VSConstants.S_OK; } } }
插入代码段,当用户类型对应的快捷然后按 tab,将代码添加到 Exec 方法。 私有方法插入代码段在后面的步骤中显示。 在上一步中添加的导航代码后面添加以下代码。
'neither an expansion session nor a completion session is open, but we got a tab, so check whether the last word typed is a snippet shortcut If m_session Is Nothing AndAlso m_exSession Is Nothing AndAlso nCmdID = CUInt(VSConstants.VSStd2KCmdID.TAB) Then 'get the word that was just added Dim pos As CaretPosition = m_textView.Caret.Position Dim word As TextExtent = m_provider.NavigatorService.GetTextStructureNavigator(m_textView.TextBuffer).GetExtentOfWord(pos.BufferPosition - 1) Dim textString As String = word.Span.GetText() 'if it is a code snippet, insert it, otherwise carry on If InsertAnyExpansion(textString, Nothing, Nothing) Then Return VSConstants.S_OK End If End If
//neither an expansion session nor a completion session is open, but we got a tab, so check whether the last word typed is a snippet shortcut if (m_session == null && m_exSession == null && nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB) { //get the word that was just added CaretPosition pos = m_textView.Caret.Position; TextExtent word = m_provider.NavigatorService.GetTextStructureNavigator(m_textView.TextBuffer).GetExtentOfWord(pos.BufferPosition - 1); //use the position 1 space back string textString = word.Span.GetText(); //the word that was just added //if it is a code snippet, insert it, otherwise carry on if (InsertAnyExpansion(textString, null, null)) return VSConstants.S_OK; }
执行 IVsExpansionClient 接口的方法。 此实现中,唯一的方法好处在于 EndExpansion 和 OnItemChosen。 其他方法应返回 S_OK。
Public Function EndExpansion() As Integer Implements IVsExpansionClient.EndExpansion m_exSession = Nothing Return VSConstants.S_OK End Function Public Function FormatSpan(ByVal pBuffer As IVsTextLines, ByVal ts As TextSpan()) As Integer Implements IVsExpansionClient.FormatSpan Return VSConstants.S_OK End Function Public Function GetExpansionFunction(ByVal xmlFunctionNode As IXMLDOMNode, ByVal bstrFieldName As String, ByRef pFunc As IVsExpansionFunction) As Integer Implements IVsExpansionClient.GetExpansionFunction pFunc = Nothing Return VSConstants.S_OK End Function Public Function IsValidKind(ByVal pBuffer As IVsTextLines, ByVal ts As TextSpan(), ByVal bstrKind As String, ByRef pfIsValidKind As Integer) As Integer Implements IVsExpansionClient.IsValidKind pfIsValidKind = 1 Return VSConstants.S_OK End Function Public Function IsValidType(ByVal pBuffer As IVsTextLines, ByVal ts() As TextSpan, ByVal rgTypes() As String, ByVal iCountTypes As Integer, ByRef pfIsValidType As Integer) As Integer Implements IVsExpansionClient.IsValidType pfIsValidType = 1 Return VSConstants.S_OK End Function Public Function OnAfterInsertion(ByVal pSession As IVsExpansionSession) As Integer Implements IVsExpansionClient.OnAfterInsertion Return VSConstants.S_OK End Function Public Function OnBeforeInsertion(ByVal pSession As IVsExpansionSession) As Integer Implements IVsExpansionClient.OnBeforeInsertion Return VSConstants.S_OK End Function Public Function PositionCaretForEditing(ByVal pBuffer As IVsTextLines, ByVal ts As TextSpan()) As Integer Implements IVsExpansionClient.PositionCaretForEditing Return VSConstants.S_OK End Function
public int EndExpansion() { m_exSession = null; return VSConstants.S_OK; } public int FormatSpan(IVsTextLines pBuffer, TextSpan[] ts) { return VSConstants.S_OK; } public int GetExpansionFunction(IXMLDOMNode xmlFunctionNode, string bstrFieldName, out IVsExpansionFunction pFunc) { pFunc = null; return VSConstants.S_OK; } public int IsValidKind(IVsTextLines pBuffer, TextSpan[] ts, string bstrKind, out int pfIsValidKind) { pfIsValidKind = 1; return VSConstants.S_OK; } public int IsValidType(IVsTextLines pBuffer, TextSpan[] ts, string[] rgTypes, int iCountTypes, out int pfIsValidType) { pfIsValidType = 1; return VSConstants.S_OK; } public int OnAfterInsertion(IVsExpansionSession pSession) { return VSConstants.S_OK; } public int OnBeforeInsertion(IVsExpansionSession pSession) { return VSConstants.S_OK; } public int PositionCaretForEditing(IVsTextLines pBuffer, TextSpan[] ts) { return VSConstants.S_OK; }
实现 OnItemChosen 方法。 帮助器方法插入扩展实际将包括在后面的步骤。 TextSpan 提供行和列信息,可以从 IVsTextView的访问。
Public Function OnItemChosen(ByVal pszTitle As String, ByVal pszPath As String) As Integer Implements IVsExpansionClient.OnItemChosen InsertAnyExpansion(Nothing, pszTitle, pszPath) Return VSConstants.S_OK End Function
public int OnItemChosen(string pszTitle, string pszPath) { InsertAnyExpansion(null, pszTitle, pszPath); return VSConstants.S_OK; }
以下私有方法插入代码段,快捷方式或基于标题和路径。 然后调用与此代码段的 InsertNamedExpansion 方法。
Private Function InsertAnyExpansion(ByVal shortcut As String, ByVal title As String, ByVal path As String) As Boolean Dim endColumn As Integer, startLine As Integer 'get the column number from the IVsTextView, not the ITextView m_vsTextView.GetCaretPos(startLine, endColumn) Dim addSpan As New TextSpan() addSpan.iStartIndex = endColumn addSpan.iEndIndex = endColumn addSpan.iStartLine = startLine addSpan.iEndLine = startLine 'get the expansion from the shortcut If shortcut IsNot Nothing Then 'reset the TextSpan to the width of the shortcut, because we're going to replace the shortcut with the expansion addSpan.iStartIndex = addSpan.iEndIndex - shortcut.Length m_exManager.GetExpansionByShortcut( Me, New Guid(SnippetUtilities.LanguageServiceGuidStr), shortcut, m_vsTextView, New TextSpan() {addSpan}, 0, path, title) End If If title IsNot Nothing AndAlso path IsNot Nothing Then Dim textLines As IVsTextLines = Nothing m_vsTextView.GetBuffer(textLines) Dim bufferExpansion As IVsExpansion = DirectCast(textLines, IVsExpansion) If bufferExpansion IsNot Nothing Then Dim hr As Integer = bufferExpansion.InsertNamedExpansion( title, path, addSpan, Me, New Guid(SnippetUtilities.LanguageServiceGuidStr), 0, m_exSession) If VSConstants.S_OK = hr Then Return True End If End If End If Return False End Function
private bool InsertAnyExpansion(string shortcut, string title, string path) { //first get the ___location of the caret, and set up a TextSpan int endColumn, startLine; //get the column number from the IVsTextView, not the ITextView m_vsTextView.GetCaretPos(out startLine, out endColumn); TextSpan addSpan = new TextSpan(); addSpan.iStartIndex = endColumn; addSpan.iEndIndex = endColumn; addSpan.iStartLine = startLine; addSpan.iEndLine = startLine; if (shortcut != null) //get the expansion from the shortcut { //reset the TextSpan to the width of the shortcut, //because we're going to replace the shortcut with the expansion addSpan.iStartIndex = addSpan.iEndIndex - shortcut.Length; m_exManager.GetExpansionByShortcut( this, new Guid(SnippetUtilities.LanguageServiceGuidStr), shortcut, m_vsTextView, new TextSpan[] { addSpan }, 0, out path, out title); } if (title != null && path != null) { IVsTextLines textLines; m_vsTextView.GetBuffer(out textLines); IVsExpansion bufferExpansion = (IVsExpansion)textLines; if (bufferExpansion != null) { int hr = bufferExpansion.InsertNamedExpansion( title, path, addSpan, this, new Guid(SnippetUtilities.LanguageServiceGuidStr), 0, out m_exSession); if (VSConstants.S_OK == hr) { return true; } } } return false; }
生成并测试代码段展开
可以测试代码段值指示在项目中工作。
生成并测试代码段展开
生成解决方案。 当您运行在调试器中查看此项目, Visual Studio 的第二个实例进行实例化。
打开文本文件并键入一些文本。
右击某处在文本然后单击 插入代码段。
代码段选择器 UI 应出现,并显示字符串 “测试替换字段”。 双击该字符串。
应插入下面的代码段。
MessageBox.Show("first"); MessageBox.Show("second");
不要按以下内容或 ESC。
tab 键和 SHIFT+TAB 切换 “首先之间”和 “接下来”。
通过按以下内容或 ESC 接受插入。
在文本的不同部分,键入 “测试”然后按 tab。 由于 “test”是代码段的快捷方式,代码段中应重新插入。