使用FileDialogAttribute可以设置FileNameEditor中的属性,基本成员如下:
属性 | 描述 | 默认值 |
FileDialogType | Save or Open | FileDialogType.Save |
Filter | Filter string for file extensions | All Files (*.*)|*.* |
Title | Dialog box title | Select propertyname |
DefaultExtension | Default file extensions | None |
CheckFileExists | True to only allow selecting existing files | False |
CheckPathExists | True to only allow using existing paths | False |
在下面这段模版代码中,我们设置了弹出的对话框的类型为打开文件对话框,标题为“Select Input File”。
2 [Editor( typeof (FileNameEditor), typeof (System.Drawing.Design.UITypeEditor)),
3 FileDialogAttribute(FileDialogType.Open, Title = " Select Input File " ),
4 Category( " Custom " ), Description( " User selected file. " )]
5 public string OpenFileName
6 {
7 get {return _openFileName;}
8 set {_openFileName= value;}
9}
10
11 执行
12
SchemaExplorer允许我们获取数据库中一些对象的信息。如果你使用的是SQL Server2000数据库,你可以通过扩展属性获取很多对象的有用的信息。例如:SQL Server定义了一个扩展属性来标识表中的唯一标识字段,在模版中可以这样写: CodeSmith定义的扩展属性包括table columns, view columns, 和 command parameters。
if( ((bool)cs.ExtendedProperties["CS_IsIdentity"].Value) == true)
{
Response.Write(cs.Name);
}
}
%>
Table columns
CS_IsIdentity
CS_IsComputed
CS_IsDeterministic
CS_IdentitySeed
CS_IdentityIncrement
CS_Default
view columns
CS_IsDeterministic
command parameters
另外,每个对象都有一个CS_Description的扩展属性。你也可以通过SQL Server中的系统存储过程sp_addextendedproperty来创建自定义的扩展属性。例如:我们执行如下命令为Customer这张表的ID字段添加一个Caption的扩展属性:
在数据库中执行完这条语句后,CodeSmith中将会在这个字段的扩展属性集合中加上Caption属性。有关SQL Server 中的扩展属性的内容请参考联机丛书。
用CodeSmith生成可变化的代码,其实是先利用CodeSmith生成一个基类,然后自定义其它类继承于该类。当我们重新生成基类时CodeSmith不要接触继承的子类中的代码。看下面的这段模版脚本: 执行该模版并输入如下数据:
<% @ Property Name = " ClassName " Type = " System.String " Description = " Name of the class. " %>
<% @ Property Name = " ConstructorParameterName " Type = " System.String " Description = " Constructor parameter name. " %>
<% @ Property Name = " ConstructorParameterType " Type = " System.String " Description = " Data type of the constructor parameter. " %>
class <%= ClassName %>
{
<%= ConstructorParameterType %> m_<%= ConstructorParameterName %>;
public <%= ClassName %>(<%= ConstructorParameterType %> <%= ConstructorParameterName %>)
{
m_<%= ConstructorParameterName %> = <%= ConstructorParameterName %>
}
}
该模版生成的代码可能如下:
2 {
3 int m_balance;
4
5 public Account(int balance)
6 {
7 m_balance = balance
8 }
9
10}
11
12
把生成的文件保存为Account.cs文件。这时我们可以编写第二个类生成Check.cs文件代码:
2 {
3 public Checking : base(0)
4 {
5 }
6}
现在如果需要改变Account Balance的类型为浮点型,我们只需要改变ConstructorParameterType属性为float,并重新生成Account.cs文件即可而不需要直接在Account.cs中进行手工修改,并且不需要修改Check.cs文件的任何代码。
CodeSmith允许我们存储元数据在XML文件中,然后在执行模版时直接打开XML文件填写到属性面板中。
1.XML Property With a Schema
2 < xs:schema targetNamespace =http://www.codesmithtools.com/PO
3 xmlns:xs =http://www.w3.org/2001/XMLSchema
4 xmlns =http://www.codesmithtools.com/PO
5 elementFormDefault ="qualified" attributeFormDefault ="unqualified" >
6 < xs:element name ="PurchaseOrder" >
7 < xs:complexType >
8 < xs:sequence >
9 < xs:element name ="PONumber" type ="xs:string" />
10 < xs:element name ="CustomerName" type ="xs:string" />
11 < xs:element name ="CustomerCity" type ="xs:string" />
12 < xs:element name ="CustomerState" type ="xs:string" />
13 < xs:element name ="Items" >
14 < xs:complexType >
15 < xs:sequence >
16 < xs:element name ="Item" maxOccurs ="unbounded" >
17 < xs:complexType >
18 < xs:attribute name ="ItemNumber" type ="xs:string" use ="required" />
19 < xs:attribute name ="Quantity" type ="xs:integer" use ="required" />
20 </ xs:complexType >
21 </ xs:element >
22 </ xs:sequence >
23 </ xs:complexType >
24 </ xs:element >
25 </ xs:sequence >
26 </ xs:complexType >
27 </ xs:element >
28 </ xs:schema >
29
30
这是一个简单的带有Schema的XML Property的例子:
利用这个Schema文件,我们可以定义一个XML Property来在运行时读去元数据。
<% @ XmlProperty Name = " PurchaseOrder " Schema = " PO.xsd " Optional = " False " Category = " Data " Description = " Purchase Order to generate packing list for. " %>
Packing List
ref : PO# <%= PurchaseOrder.PONumber %>
Ship To:
<%= PurchaseOrder.CustomerName %>
<%= PurchaseOrder.CustomerCity %> , <%= PurchaseOrder.CustomerState %>
Contents:
<% for ( int i = 0 ; i < PurchaseOrder.Items.Count; i ++ ) { %>
<%= PurchaseOrder.Items[i].ItemNumber %>, Quantity <%= PurchaseOrder.Items[i].Quantity %>
<% } %>
在运行时,PurchaseOrder属性在属性面板中显示为按钮,单击后弹出一个对话框供用户选择XML文件。
选择一个XML文件。在该例子XML文件内容如下:
2 < PurchaseOrder xmlns =http://www.codesmithtools.com/PO
3 xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" >
4 < PONumber > 5271 </ PONumber >
5 < CustomerName > John Nelson </ CustomerName >
6 < CustomerCity > Gamonetta </ CustomerCity >
7 < CustomerState > MS </ CustomerState >
8 < Items >
9 < Item ItemNumber ="HM85" Quantity ="12" />
10 < Item ItemNumber ="JR82" Quantity ="4" />
11 < Item ItemNumber ="PR43" Quantity ="6" />
12 </ Items >
13 </ PurchaseOrder >
14
15
生成后的代码如下:
ref: PO#5271
Ship To:
John Nelson
Gamonetta, MS
Contents:
HM85, Quantity 12
JR82, Quantity 4
PR43, Quantity 6
2.XML Property Without a Schema
这是一个不带Schema的XML Property的例子。这个模版在运行时可以访问任何XML文件。
<% @ XmlProperty Name = " TargetFile " Optional = " False " Category = " Data " Description = " XML file to iterate. " %>
<% @ Assembly Name = " System.Xml " %>
<% @ Import Namespace = " System.Xml " %>
Top - level nodes:
<% Dim currNode as XmlNode
currNode = TargetFile.DocumentElement.FirstChild
Do Until currNode Is Nothing %>
<%= currNode.InnerXml %>
<% currNode = currNode.NextSibling()
Loop %>
概莫版对目标文件的属性并没有定义一个Schema,所以属性在模版中是作为一个XMLDocument。如果我们选择的XML文件如下所示:
2 < Books >
3 < Book > UML 2.0 In a Nutshell </ Book >
4 < Book > The Best Software Writing </ Book >
5 < Book > Coder to Developer </ Book >
6 < Book > Code Complete </ Book >
7 </ Books >
生成后的代码:
UML 2.0 In a Nutshell
The Best Software Writing
Coder to Developer
Code Complete
在使用CodeSmith进行代码生成的时候,你可能需要在子模版和父模版之间共享属性。比如,写一个基于数据库生成代码的模版,在每个模版里面都定义了一个名为Server的属性。当你在父模版中使用此属性时,它的值只对父模版起作用。想要设置此值到子模版,可以在父模版中使用CopyPropertiesTo方法,当在父模版中使用此属性时,它的值会发送到子模版中去。下面这段代码展示了如何使用该方法:
Header header = new Header();
// copy all properties with matching name and type to the sub-template instance
this .CopyPropertiesTo(header);
在CodeSmith中,要把生成的代码文件输出到文件中,你需要在自己的模版中继承OutputFileCodeTemplate类。
<% @ Assembly Name = " CodeSmith.BaseTemplates " %>
OutputFileCodeTemplate主要做两件事情:
1.它添加一个名为OutputFile的属性到你的模版中,该属性要求你必须选择一个文件;
2.模版重载了方法OnPostRender(),在CodeSmith生成代码完成后把相应的内容写入到指定的文件中去。
如果想要自定义OutputFile属性弹出的保存文件对话框,你需要在你的模版中重载OutputFile属性。例如:你希望用户选择一个.cs文件来保存生成的代码,需要在你的模版中添加如下代码:
// Override the OutputFile property and assign our specific settings to it.
[FileDialog(FileDialogType.Save, Title = " Select Output File " , Filter = " C# Files (*.cs)|*.cs " , DefaultExtension = " .cs " )]
public override string OutputFile
{
get {return base.OutputFile;}
set {base.OutputFile = value;}
}
</ script >
在CodeSmith中,CodeTemplate.Render方法是在模版执行完成进行模版输出时执行,你可以通过重载CodeTemplate.Render方法来修改CodeSmith输出时的事件处理。例如:你可以修改模版输出时的方式来代替现在默认的方式,下面这段代码展示了在保持CodeSmith默认的窗口显示的同时,把结果输出到两个不同的文件。 注意不能忘了base.Render(writer);这句话,否则你将不能获得默认的输出。当重载CodeTemplate.Render方法时,你也可
以访问TextWriter,也就是说你也可以直接添加其它的附属信息到模版输出的内容中。
2 <% @ Import Namespace = " System.IO " %>
3 This template demonstrates using the AddTextWriter method
4 to output the template results to multiple locations concurrently.
5 < script runat = " template " >
6 public override void Render(TextWriter writer)
7 {
8 StreamWriter fileWriter1 = new StreamWriter(@"C:/test1.txt", true);
9 this.Response.AddTextWriter(fileWriter1);
10
11 StreamWriter fileWriter2 = new StreamWriter(@"C:/test2.txt", true);
12 this.Response.AddTextWriter(fileWriter2);
13
14 base.Render(writer);
15
16 fileWriter1.Close();
17 fileWriter2.Close();
18}
19 </ script >