Visual Studio 插件的开发(转)
起因
在做项目的时候,经常需要根据表结构create一些实体类,写多了,实在是觉得无趣,于是就琢磨着做个代码生成工具。当然现在有很多现成的,拿来用就好,可是总想自己弄个出来玩玩,一来是当初用DataSet,VS可以根据一个xsd文件生成那么多代码,可以拖拖拽拽就搞定,一直没闹明白是怎么做的,不甘心,总想弄明白,二来,公司里,数据库的脚本大多是根据一个xml配置文件生成的,这样,我拿到这个xml生成代码也是挺方便的。
学习
有了这个想法,可完全没头绪该怎么开发VS add-in, 无奈,只能仰仗Google大神了,“VS 插件”, “自动代码生成 vs site:cnblogs.com” … 等等,一顿狂搜,了解到了相关的技术有:VS Add-in, CodeDom, T4, Template, Visual Designer, Domain-Specific Languages, Custom tools, etc.
VS Add-in: 可以使用任何.Net语言开发VS的插件,可以操作开发环境中的任何元素:解决方案,项目,文件,菜单,Solution Explorer, Output window…
CodeDom: 代码文档对象模型。类似Xml的Dom操作,CodeDom将代码转换成一种数据结构,通过操作这种数据结构可以实现生成代码,修改代码,动态编译等等各种功能。
T4: Text Templating Transformation Toolkit, 通过模板加代码的方式产生代码,可以想象下aspx页面,里面有html代码,也有.Net代码,通过转换,最后呈现出html页面。
Template: 模板,在添加新项的时候,在对话框中的那些就是模板。
Visual Designer: 像类型化DataSet,它有一个可视化的编辑界面,通过拖拽,点几下鼠标等等操作就可以设计出我们想要的DataSet类型。
Domain-Specific Languages: 特定领域模型语言,通过它,我们可以设计出Visual Designer。
Custom Tools: 自定义工具,通过一个文件生成另一个文件。
实践
CodeDom太复杂,用来生成代码如果杀鸡用牛刀,Visual Designer, Domain-Specific Languages,嗯,也用不到,暂时我不需要做个可视化的界面去设计我的代码,等我哪天要实现个类似类型化DataSet那样的插件的时候再考虑吧。去掉那些复杂的东西,我现在要用到的技术有:VS Add-in,用来实现VS的插件,使代码生成工具集成进VS;T4, 用来产生代码; Template,定义一个模板。
先说T4,看个简单的列子:
首先创建一个项目,然后添加新项,选择文本模板
文件里包含如下代码
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".txt" #>
在文本模板中,<#@ #>中是指令,定义了模板的一些行为,如第二行,output extension=”.txt”,意思是说,该模板最后转换生成的文件的后缀是.txt的。当然,我需要的代码文件,所以将其改为.cs即可。将文本修改成下面这个样子:
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
using System;namespace T4
{
public class T4Test
{
}
}
保存后,可以看到Solution Explorer里面多了一个.cs文件
打开cs文件,可以看到里面包含如下代码,跟我在模板文件里的内容一样。
using System;
namespace T4
{
public class T4Test
{
}
}
关于T4的语法,cnBlogs里有太多解释,这里就不更进一步的描述了。
可是,这样一个模板文件产生的代码是固定的,而我需要的是输入一段xml,根据xml来生成相应的代码文件。要使模板文件知道xml里的内容,则需要将其内容作为参数传递到模板里,这个时候就需要用到参数指令:
<#@ parameter type="" name="" #>
然后再将之前的模板修改为:
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<#@ parameter type="System.String" name="className" #>
using System;namespace T4
{
public class <#= className #>
{
}
}
如果这个时候,点击保存,VS会提示你转换失败,因为输入的参数为空。这个时候,需要修改模板文件的属性,在自定义工具里,我们可以看到显示的是TextTemplatingFileGenerator,它负责将模板文件转换成目标文件。但是在这里,我需要的是将模板转换成代码生成类,将该属性修改为:TextTemplatingFilePreprocessor。这个时候再保存,就会发现原来的cs文件里的内容变成了一段长的代码:
namespace Test
{
using System;
#line 1 "E:\My Files\Documents\Visual Studio 2010\Projects\MStarGATDataEntityGenerator\NUTest.GAT.Common\TextTemplate1.tt"
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "10.0.0.0")]
public partial class TextTemplate1 : TextTemplate1Base
{… …
记得原来用VS2003的时候,还没有T4技术,那个时候也写了一个代码生成工具,那个幸苦啊,一行行的WriteLine,又要控制输出代码的缩进,长长的一大段代码。现在TextTemplatingFilePreprocessor工具将模板自动的生成了那个类,工作强度上轻松多了。在这个TextTemplate1类里有个TransformText的方法,调用它,就会根据模板输出代码。不过现在还不能直接去调用,否则还是会出现跟使用TextTemplatingFileGenerator工具时一样的错误。因为,我们还是没有设置className变量的值。可是找遍整个TextTemplate1类,既没有在构造函数里发现参数可以设置,也没发现公共属性,也没方法,只有一个私有的_classNameField变量。好在生成的TextTemplate1类是partial的,我们可以自己定义一个属性去设置className,然后再调用TransformText方法。比如设置className为“Table”,我们将得到代码:
using System;
namespace T4
{
public class Table
{
}
}
好了,到此,关于T4要用到的知识就这些了。
下面就是VS Add-in了。前面说了,我想当在VS里添加了一个新文件,然后将一段xml复制到文件里,然后保存,最后就能得到代码文件。前面T4已经可以帮助我实现生成代码文件,现在我需要的是可以让我在保存文件的时候将文件的内容传递给TextTemplate1类,然后调用TransformText方法,然后将得到的代码内容保存到一个cs文件中,并添加到项目里。而这些工作就得依靠VS Add-in来帮我实现了。
首先,我们需要添加一个VS Add-in的项目
找到Connect.cs文件,在OnConnection方法中,添加以下代码
DocumentEvents docMasterEvents = this.application.Events.get_DocumentEvents(null);
docMasterEvents.DocumentSaved += new _dispDocumentEvents_DocumentSavedEventHandler(
docMasterEvents_DocumentSaved);
以及方法
void docMasterEvents_DocumentSaved(Document Document)
{
if (Document == null) return;
if(!Document.Name.ToLower().EndsWith(“.xml”)) return;TextTemplate1 gen = new TextTemplate1();
gen.className = “Table”;
string code = gen.TransformText();
// todo: 将代码写入到文件里,并添加到项目中
}
在上面的DocumentSaved方法里,如果发现文件后缀是xml的,就去调用模板。这里有个问题,那就是,会对所有的xml都去调用。可是在一个项目里总会有些其他的xml文件,这些文件是不需要转换的。当然可以对文件内容进行判断,再决定要不要调用模板,不过更简单的方法是用一个特殊的文件名,而不是用.xml。比如在我的项目里,我使用.msgatde作为文件名后缀。讲到这里,又该介绍下模板了,这里的模板是指添加新项时,那些可选择的项目。
为什么要讲模板呢,本来实现这个代码自动生成的工具就是图个方便,可如果每次都要自己将新建的xml文件的后缀改成我自己定义的那个后缀,多麻烦,说不定还很容易写错。所有为了更一步简化操作,我打算定义一个模板,这样在添加新项的时候,就自动生成一个.msgatde后缀的文件。
一个模板里,一般会至少包含3个文件:
第一个,图标文件,在对话框里显示用的。
第二个,模板文件,添加新项后,VS会根据这个文件产生新的文件添加到项目中。
第三个,模板描述文件。
现在来看下第三个文件的内容:
其中ProjectItem那一段即定义了模板的行为:通过模板里的DataEntity.msgatde文件产生目标文件$fileinputname$.msgatde。
在这些文件编辑好后,需要将其打包成一个zip文件,并将其放置到$my documents$\Visual Studio 2010\Templates\ItemTemplates\Visual C#目录下。现在在选择添加新项,即可看到我们定义的模板了。
ok,讲完了怎么定义一个模板,现在该接着讲VS Add-in了。在前面的DocumentSaved方法里还没有实现如何将生成的代码添加到项目里,现在接着说。
首先,需要将得到的代码保存到文件里,这里就有一个问题了,如何知道路径呢?在DocumentSaved方法中,有一个Document的参数,这个就是表示了当前的文档,Document有个属性ProjectItem,通过该属性可以获取到当前文件的路径:
string fullname = Document.ProjectItem.Properties.Item(“FullPath”).Value.ToString();
知道了路径,就容易多啦:
string codeFile = fullname.Repleace(“.msgatde”, “.cs”);
using(StreamWriter sw = new StreamWriter(codeFile))
{
sw.Write(codeString);
}
现在文件是有了,该把它加到项目里了,很简单:
Document.ProjectItem.ProjectItems.AddFromFile(codeFile);
说到这个方法,要顺便说一句。都知道当我们添加了一个.aspx文件后,会自动产生一个.aspx.cs的文件,并且这个文件会存在于.aspx文件下,这是个很酷的特性,之前在搜索如何实现的时候,网上给出了大致有3种方法,如修改preject file的内容,添加dependupon元素,或者修改注册表等方法,其实不用那么麻烦,通过上面的方法,.cs文件自动被添加到.msgatde文件下面了,效果如下:
最后讲下部署插件,在插件的项目里,有个{prjoectname}.AddIn文件,将其copy到\Documents\Visual Studio 2010\Addins目录下,然后将其用文本编辑软件打开:
其中第十行是说明该插件的dll文件所在的路径,将其修改为正确的路径。当然,你也可以将文件也复制到该目录下。
ok,目前关于如何创建一个代码生成插件的部分就讲完了。这里只是记录了我在学习如何创建这个插件过程中遇到的难点,很多细节部分并没有写下来,还有很多东西需要完善,比如每次生成代码,可以把生成的结果输出到output window,如果出错了,也把错误的原因output出来。
private void OutputToOPW(string format, params object[] objs)
{
OutputWindow ow = this.applicationObject.ToolWindows.OutputWindow; // applicationObject 是 一个DTE2对象
OutputWindowPane owp = null;
try
{
owp = ow.OutputWindowPanes.Item("MyAddin");
}
catch
{
owp = ow.OutputWindowPanes.Add("MyAddin");
}
owp.Activate();
owp.OutputString(string.Format(format, objs));
}
最后,推荐一本书:《Practical.Code.Generation.in.NET》。多亏了这本书,才解决了我之前的很多困扰。
原文:http://www.cnblogs.com/FMax/archive/2011/07/09/2101699.html
Visual Studio 插件的开发(转)的更多相关文章
- .Net Core 常用开发工具(IDE和运行时、Visual Studio插件、Visual Studio Code插件)
IDE和运行时 组件名 描述 可选版本 推荐版本 Visual Studio Community 社区免费版 For Visual Studio 2017 For Visual Studio 2019 ...
- 12款好用的Visual Studio插件,最后一款良心推荐
目录 01 CodeMaid 02 Markdown Editor 03 ReSharper 04 GitHub Extension for Visual Studio 05 ZenCoding 06 ...
- [入门级] visual studio 2010 mvc4开发,用ibatis作为数据库访问媒介(一)
[入门级] visual studio 2010 mvc4开发,用ibatis作为数据库访问媒介(一) Date 周二 06 一月 2015 By 钟谢伟 Tags mvc4 / asp.net 示 ...
- Visual Studio 2013 Web开发
cnbeta新闻:微软正式发布Visual Studio 2013 RTM版,微软还发布了Visual Studio 2013的最终版本..NET 4.5.1以及Team Foundation Ser ...
- 安装和配置SVN服务器Subversion、客户端TortoiseSVN和Visual Studio插件AnkhSvn
1.下载并安装服务器端Subversion下载地址:http://subversion.apache.org当前最新版本为1.8.10,默认安装目录为C:\Program Files\Subversi ...
- Visual Studio 2013 Web开发、新增功能:“Browser Link”
微软正式发布Visual Studio 2013 RTM版,微软还发布了Visual Studio 2013的最终版本..NET 4.5.1以及Team Foundation Server 2013. ...
- Visual Studio 2012 应用软件开发新方式
微软正式发布Visual Studio 2012 应用软件开发新方式 2012-09-13 09:54 51CTO.com 我要评论(0) 字号:T | T “现在,开发者将有更好的机会开发与云服务连 ...
- Visual Studio 2013 Web开发、新增功能:“Browser Link”
微软正式发布Visual Studio 2013 RTM版,微软还发布了Visual Studio 2013的最终版本..NET 4.5.1以及Team Foundation Server 2013. ...
- 在 Visual Studio 2010 中开发和部署 Windows Azure 应用程序
原文 在 Visual Studio 2010 中开发和部署 Windows Azure 应用程序 在 Visual Studio 2010 中开发和部署 Windows Azure 应用程序 Jim ...
随机推荐
- 【Alpha版本】十天冲刺——日志集合贴
No Bug 031402401鲍亮 031402402曹鑫杰 031402403常松 031402412林淋 031402418汪培侨 031402426许秋鑫 Day1 Day2 Day3 Day ...
- 5 构建Mysql+heartbeat+DRBD+LVS集群应用系统系列之生产环境下drbd裂脑处理
preface 公司的业务变更,导致服务器要搬迁,所以需要关闭服务器,然后到新地在开启服务器. 关机前确定drbd+heartbeat+mysql是正常使用的,没有异常,Heartbeat和drbd都 ...
- Android开发笔记之《远程控制(MQTT|mosquitto) && (ProtocalBuffer | GRPC)》
Android推送方案分析(MQTT/XMPP/GCM): http://www.open-open.com/lib/view/open1410848945601.htmlMQTT官网: http:/ ...
- c#.Net:Excel导入/导出之NPOI 2.0简介
NPOI 2.0+主要由SS, HPSF, DDF, HSSF, XWPF, XSSF, OpenXml4Net, OpenXmlFormats组成,具体列表如下: 资料来自:百度百科 Ass ...
- dos 固定ip命令
dos 固定ip命令 ***************************************************************************************** ...
- 第二轮冲刺-Runner站立会议06
今天:解决连接问题 明天:编写日历界面 困难:暂无
- 【转】JavaWeb MVC
-------------------------------------------------------------------------------------------------- 1 ...
- FireFox每次访问页面时检查最新版本
FireFox每次访问页面时检查最新版本 浏览器都有自己的缓存机制,作为开发人员,每次js的修改都要清空缓存,显然很不方便.而firefox并没有提供ie那样的设置. 下面的方法就可以非常方便的设置f ...
- nginx虚拟主机配置笔记
1.添加配置文件 /etc/nginx/sites-available/ 下新建文件 phpmyadmin 文件内容 server { listen 80; listen [::]:80; serve ...
- webview滑动事件 与内部html左右滑动事件冲突问题的解决办法
最近在做个混合app , 用html做页面,然后通过webview嵌套在activity中,效果是这样: 开始还是比较顺利,增加了菜单退出按钮,返回键页面回退功能,页面加载显示加载图标(在app端实现 ...