Visual Studio 代码窗体中的自动变量替换






4.85/5 (7投票s)
本文介绍如何创建一个插件,在 Visual Studio 中更改或添加代码时自动替换变量。
注意:演示文件需要放在 "C:\Documents and Settings\user\My Documents\Visual Studio 2005\Addins" 目录中。
引言
本文介绍如何将变量替换添加到代码片段生成的代码中,甚至可以实现简单的复制粘贴功能。
首先,我们需要捕获 IDE 的代码更改事件,需要有一个机制让我们查找要替换的值。现在,我们需要替换插入的代码。这还将允许我们将此功能用作内联变量替换,就像 Word 使用自动更正一样。
其次,我们需要此机制与代码片段工具协同工作。这需要我们以不同的方式包装我们的变量。代码片段使用美元符号($)来前后缀变量,使其看起来像这样:$username$。我们将使用百分号(%),如下所示:%username%,以便在代码片段设计中添加静态和变量值。
第三,我们希望在 XML 查找文件中所做的任何更改都能立即反映在 IDE 中,这需要我们使用“FileSystemWatcher
”。如果文件发生更改,其内容将自动重新加载到代码片段观察器中。
背景
您是否曾想在代码片段代码中添加变量,这些变量可以在将代码添加到 IDE 代码窗格时进行替换?我想利用 VS2005 代码片段的内置功能,并结合一个可重用的查找值模板,代码片段可以在插入代码之前进行查找。如果您查看大量的代码片段示例,您很可能会看到如何创建“header.snippet”的示例;请参见下文。下面的代码片段是我为说明这一点而组合的示例。
代码片段的根本问题是,您无法将变量链接到值查找列表,例如日期(日期格式)、时间或用户名,因此您必须将这些值硬编码到代码片段中,或者使默认值不可编辑。这基本上是添加值,而不必在值上方显示编辑框。此项目解决了这个问题,并为代码片段库打开了无限的可能性。
代码片段代码示例
用于生成代码块标题部分的示例代码片段
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets
xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>Header</Title>
<Shortcut>Header</Shortcut>
<Description>Code snippet Header statement</Description>
<Author>Grant Simms</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal default="true" Editable="true">
<ID>classname</ID>
<Default>ClassName</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[#region Header
//===================================================================
// Author: %username%
// Date: %date% time %timestamp%
// Description: $classname$ , Description:
//
//
// %copyright%
//===================================================================
#endregion $end$ ]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
这唯一的问题是,您现在必须输入数据到字段中,即日期、用户名以及其他可能无法作为代码片段中的变量的其他信息。
上面的示例是代码片段完成后您将看到的,图 1.0。通过制表符,您可以从一个块移动到另一个块;但是,如果您可以有一个流程,通过自动替换预定义的变量及其相应的数据来消除这个繁琐的过程,请参见图 1.1,那么这个过程将更简单/更快。
图像
图 1.0
图 1.1
按键操作
此流程的强大功能允许广泛的使用,从简单的复制粘贴操作,可以将用百分号(%)括起来的变量查找并替换。如果您想输入一个变量,例如 %username%,然后按 Enter,它将被转换为您在 XML 文档中放置的值,例如您的名字。
private void Form1_Load(object sender, EventArgs e)
{
%username%
}
private void Form1_Load(object sender, EventArgs e)
{
Grant Simms
}
XML 文档在 IDE 启动时加载,以便值始终可用,这有助于提高速度。我还添加了一个 FileSystemWatcher
,以便在文件发生更改时重新加载 XML 文件,从而使新变量或更新的变量立即可用。我利用了正则表达式算法来快速查找和替换值。
关注点
捕获 IDE 代码更改事件的代码如下。这必须放在 OnConnection
调用中。这也是需要将变量加载到 StringDictionary
中以便稍后快速访问的地方。
_textEditorEvents = (TextEditorEvents)
((Events)_applicationObject.Events).get_TextEditorEvents(null);
_textEditorEvents.LineChanged += new
_dispTextEditorEvents_LineChangedEventHandler(
_textEditorEvents_LineChanged);
调用 _textEditorEvents_LineChanged
事件的代码如下
void _textEditorEvents_LineChanged(TextPoint StartPoint,
TextPoint EndPoint, int Hint)
{
//IF you want to write a status on the IDE Status bar.
// _applicationObject.StatusBar.Text = "Line Changing...";
EditPoint ep = EndPoint.CreateEditPoint();
EditPoint sp = StartPoint.CreateEditPoint();
sp.CharLeft(1);
string txt = sp.GetText(ep);
try
{
MatchCollection matches = Regex.Matches(txt, "%.*%");
if (matches.Count > 0)
{
foreach (Match match in matches)
{
sp.Delete(ep);
string newtext = txt;
IEnumerator myEnum = _stringDictionary.GetEnumerator();
foreach (DictionaryEntry de in _stringDictionary)
{
switch (de.Key.ToString())
{
case "%date%":
newtext = newtext.Replace(de.Key.ToString(),
DateTime.Now.ToString(de.Value.ToString()));
break;
case "%datetimestamp%":
goto case "%date%";
case "%timestamp%":
goto case "%date%";
default:
newtext = newtext.Replace(de.Key.ToString(),
de.Value.ToString());
break;
}
}
sp.Insert(newtext);
return;
}
}
}
catch
{
//Not going to trap anything...
}
}
设置 FileSystemWatcher
如果您想监视目录中文件的更改,则需要将 FileSystemWatcher
指向该文件并启用 EnableRaisingEvents
,然后捕获事件并执行您需要执行的操作。
#region fileSystemWatcher
fileSystemWatcher.BeginInit();
fileSystemWatcher.EnableRaisingEvents = true;
fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
fileSystemWatcher.Filter = filename;
fileSystemWatcher.IncludeSubdirectories = false;
fileSystemWatcher.Path =
System.IO.Path.GetDirectoryName(asmbly.Location);
fileSystemWatcher.Changed+=new
FileSystemEventHandler(fileSystemWatcher_Changed);
fileSystemWatcher.EndInit();
#endregion
这是您捕获事件的地方
void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
//This may fire the event more than once,
//this is due to the attributes of
//the file also updating...
LoadVariables();
}
演示项目是完全可运行的发布版本,但我包含了所有源代码来复制整个插件。
祝您编码愉快,希望这对您创建大量可重用的、可扩展的代码片段库有所帮助。
注意事项与待办功能
如果您觉得这有用,或者有任何建议可以在下一版本中改进它,请告诉我。