代码改变世界

谈谈VS中的模板

2009-01-18 22:51 Anders Cui 阅读(...) 评论(...) 编辑 收藏

基本上,我们每次在VS中新建一个项目(Project)或项(Item)的时候,都用到了它的模板。这些模板给我们提供了一个好的开始。如果你曾经历过从ASP.NET Web Application到AJAX Web Application的升级,就会对此有所体会;如果你是一个开源爱好者,需要在项目中应用大量的开源组件,那么每次的添加引用和配置也会让人厌烦。模板给我们节省了很多时间,并能使同类型的项目/项保持一致。

在VS中我们可以很方便地导出项目/项模板,可以参考下面两篇文章:

在VS2005中创建项目模板来提高开发效率

制作Visual Studio项目模板

本文将介绍模板的更多内容。

什么是项目/项模板

项目模板包含了创建特定类型的项目所需的必要文件(包括引用)。VS本身就提供了很多内置的项目模板,如Console Application, Class Library和ASP.NET Web Application等等。大部分项目模板基于一种特定的语言,如C#、F#等,同时针对特定的领域,如Windows、Web和Test等等,它们正是以此进行分类组织:

add-new-proj

这里,创建一个控制台应用程序,

create-a-console-application

基本的引用已经添加完毕,并且有了一个Program.cs文件,接下来就可以在Main函数编写代码了。

项模板用于创建逻辑上的单个文件(有时可能是创建了多个文件,比如Web Form模板,不过它们在逻辑上仍被看作单个文件)。这个过程就不再赘述了。

项目/项模板简析

现在该了解一下这些模板是如何实现的了。前面提到,VS内置了很多模板,那就看看它们是怎么做的。

先来看项目模板,内置的项目模板位于[VS2008 Path]\Common7\IDE\ProjectTemplates,这里可以看到几个以语言名称命名的文件夹,进入CSharp,则是Windows、Web、Test等文件夹,这是前面提到的模板组织方式。继续下去,打开Windows\1033文件夹,可以看多几个zip文件包。从文件名可以想到,VS当中看到的模板就是这里的一个zip包。

事实正是如此。解压缩ConsoleApplication.zip文件,这里有四个文件:

contents-of-console-template

.cs和.csproj文件就是创建项目后得到的文件,那vstemplate文件呢?它是模板的组织者,没有它,zip包就只是几个零散的文件而已。这个文件称为模板清单(Template Manifest),它实际上就是一个XML文件。

项模板的情况与此类似,它们位于[VS2008 Path]\Common7\IDE\ItemTemplates。

模板清单(Template Manifest)

清单文件是XML文件,它的Schema文件是[VS2008 Path]\XML\Schemas\1033\vstemplate.xsd,通过xsd文件我们可以了解清单文件的结构。

它的根节点是<VSTemplate>,该节点有两个Attribute:

  • Type:指定模板类型(项目模板还是项模板),取值可以是Project、ProjectGroup或Item;
  • Version:模板所用于的.NET Framework版本号。

该节点在Class文件的模板中是这样的:

<VSTemplate Version="3.0.0" Type="Item" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
</VSTemplate>

<VSTemplate>节点可以有四种子节点:

  • <TemplateData>:必选项,包含了模板的基本信息,如名称、图标、默认名称等。
  • <TemplateContent>:必选项,指定了模板所包含的文件。
  • <WizardData>:可选项,包含了传给自定义向导的XML数据。
  • <WizardExtension>:可选项,包含了一些自定义模板向导的信息。

由于这些节点包含的信息比较多,这里只好偷懒了,它们在MSDN的链接分别是:

另外还可以看看Visual Studio Templates主页项目模板和项模板之间的区别

有了上面这些知识,就可以对清单文件有全面的认识了,下面来看看如何创建模板。

创建模板

项目模板和项模板的创建有所不同,但是都有两种方式:自动方式和手工方式。使用自动方式,跟随VS的向导创建模板,而使用手工方式,则需要编写一些代码,尤其是前面提到的清单文件。一般情况下,自动方式更为简单、快捷,而手工方式则更为强大和灵活。

手工方式创建模板

其过程包含三个步骤:

  • 创建模板所包含的文件;
  • 创建清单文件,编写代码对模板进行配置;
  • 部署。

首先创建一个类库项目,它的结构如下所示:

myclasslib-arch

接下来在MyClassLibTemplate.vstemplate文件内对模板进行配置:

XML Code - 第一个模板清单文件
<VSTemplate Version="2.0.0" Type="Project" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
    
<TemplateData>
        
<Name>My ClassLib Template</Name>
        
<Description>A simple class library template</Description>
        
<ProjectType>CSharp</ProjectType>
        
<ProjectSubType></ProjectSubType>
        
<SortOrder>1000</SortOrder>
        
<CreateNewFolder>true</CreateNewFolder>
        
<DefaultName>MyClassLibProj</DefaultName>
        
<ProvideDefaultName>true</ProvideDefaultName>
        
<LocationField>Enabled</LocationField>
        
<EnableLocationBrowseButton>true</EnableLocationBrowseButton>
        
<Icon>ufo.ico</Icon>
    
</TemplateData>
    
<TemplateContent>
        
<Project TargetFileName="MyClassLib.csproj" File="MyClassLib.csproj"
                 ReplaceParameters
="true">
            
<ProjectItem TargetFileName="SampleClass.cs" ReplaceParameters="true" >
                SampleClass.cs
            
</ProjectItem>
            
<Folder Name="Properties" TargetFolderName="Properties">
                
<ProjectItem ReplaceParameters="true" TargetFileName="AssemblyInfo.cs">
                    AssemblyInfo.cs
                
</ProjectItem>
            
</Folder>
        
</Project>
    </TemplateContent>
</VSTemplate>


最后是部署。将所有这些文件放在一起(如果有文件夹,要保持它的层次结构),打包为zip文件。将文件拷贝到下面两个路径之一:

  • 如果是项目模板,拷到[My Documents Path]\Visual Studio 2008\Templates\ProjectTemplates;
  • 如果是项模板,拷到[My Documents Path]\Visual Studio 2008\Templates\ItemTemplates。

由于刚才创建的模板是项目模板,所以放在第一个路径下。然后打开VS 2008,新建一个项目,在My Templates下可以看到我们自定义的模板:

add-a-custom-project

关于以自动(向导)方式创建模板,可以参考本文开头提到的两篇文章。

自定义模板

前面的例子很简单,甚至是过于简单了。在真实的开发中,可能需要向模板传递一些参数。

首先,需要在文件中插入占位符,如$Author$,Author就是参数的名称。看下面的例子:

C# Code - 设置模板参数占位符
namespace ClassLibrary1
{
    
// Company: $Company$
    
// Created By: $Author$
    public class SampleClass
    {
    }
}


接下来需要在模板清单文件中定义这些参数和它们的值,向<TemplateContent>节点中添加<CustomParameters>节点:

XML Code - 设置参数值
<CustomParameters>
    
<CustomParameter Name="$Company$" Value="my company" />
    
<CustomParameter Name="$Author$" Value="Anders Cui" />
</CustomParameters>


好了,现在重新部署这个模板,添加一个新项目,得到的文件是:

C# Code - 使用参数之后
namespace ClassLibrary1
{
    
// Company: my company
    
// Created By: Anders Cui
    public class SampleClass
    {
    }
}


需要注意的是,相关ProjectItem的ReplaceParameters特性值要为“true”。现在,如果模板中有10个文件用到了$Author$,就能节省不少时间了,不过我还是不满足,能不能在运行时获取用户的输入呢?看看下一节关于向导的内容。

自定义模板向导

VS模板的一个增强特性就是自定义向导,这些向导可以在用户由模板创建项目/项的时候运行。向导的好处在于可以:

  • 收集用户的输入信息;
  • 向模板添加参数值;
  • 向项目添加其它文件;

使用模板向导,可以访问DTE对象(Development Tools Extensibility,是Visual Studio自动化对象模型中的主对象),从而可以方便地操作项目。创建模板向导的基本步骤为:

  • 创建一个程序集,它要实现IWizard接口;
  • 将该程序集注册到GAC(Global Assembly Cache);
  • 更新模板清单文件,使用该程序集。

这里将继续使用上面的例子,不过这次要从用户界面收集参数值,而不是把它们放在模板清单中。

先来实现IWizard接口,该接口有6个方法,这些方法会在项目模板生命周期的特定时刻执行,其中的部分方法仅适用于项模板,它们的详情请参考:IWizard成员

当Visual Studio开始创建项目时,它立即调用RunStarted方法,因此该方法是收集用户输入信息的良好位置。它有四个参数:

  • Object 参数,可强制转换为根 _DTE 对象,以使您能够自定义项目。
  • Dictionary 参数,它包含模板中所有预定义参数的集合。
  • WizardRunKind 参数,它包含有关所使用的模板种类的信息。
  • Object 数组,它包含通过 Visual Studio 传递给向导的一组参数。

在本例中,将来自用户的输入添加到Dictionary参数中。好了,现在可以开始编码了,新建一个类库项目,名称为CustomTemplateWizard,新建一个Windows Form,用来接受用户输入,界面大体如下:

其代码为:

C# Code - 接受用户输入的窗体


下面的类WizardImpl实现了IWizard接口:

C# Code - 实现IWizard接口的类WizardImpl


然后,编译项目,为项目添加强命名,接着注册到GAC(Global Assembly Cache)。

接下来要修改模板清单文件,来使用新出炉的程序集,这要在</TemplateContent>之后添加:

XML Code - 添加对程序集的引用


这些都完成后,跟前面一样,打包、部署,然后打开VS,新建一个项目,此时出现一个对话框,在这里输入信息:

info-collector2

点击确定,生成的文件中可以看到参数已被替换:

replacedfile

初学者工具包(Starter Kits)

初学者工具包是一种特殊的项目模板,用于与其他开发人员分享示例代码和代码资源,可以看作是加强版的项目模板。初学者工具包往往包含了项目模板的所有内容,还可能包含额外的文档内容。

小结

本文首先简单介绍了项目/项模板的概念,然后介绍了模板及其清单文件的结构,在此基础上演示了如何手工创建并部署模板。最后讨论了两种更为灵活和强大的方式:向模板传递参数以及自定义模板向导,后者借助于DTE对象可以完成很复杂的功能。

参考

《Professional Visual Studio® 2008 Extensibility》

MSDN