CodeSmith基础(八)
编写CodeSmith自定义属性的编辑器(Writing Custom Property Editors)
当你开始编写自定义的CodeSmith模板时,很可能对于使用它的strings或integers属性很满意,但有时你会发现需要创建一个不同类型的属性,可能是一个自定义的类型或者是.NET framework中但是在属性面板中没有提供的类型。在模板中去作这些很简单,但是怎样指定一个类型在运行模板时显示在属性面板中呢?例如创建了一个Person类并且具有很多不同的属性,但是却没有办法让用户去组装这个类……除非创建一个自定义属性编辑器。
属性面板提供了方法去编写自定义的属性编辑器,当用户在面板上选择一个属性时可以激发相应的方法,同时也可以通过编写代码实现提示用户输入一个必要的值。下面我们举个例子,创建一个接受组建的属性并且是用影射循环贯串所有的类,是所有的类都可以使用它和它的方法,去创建一个NUnit测试基础。(这句翻译的不好,原文:As an example we are going to build a template which accepts an assembly as a property and then using reflection loops through all of the classes, and the methods of those classes, to build NUnit test stubs.)
首先,我们来关注一下模板的组件属性,暂且不看自定义编写的代码。模板的第一部分是一些声明定义和属性。将属性放在脚本标签中代替使用属性声明,在下一部分将看到这样做的必要。
<%
@CodeTemplateLanguage
=
"
C#
"
TargetLanguage
=
"
C#
"
Description
=
"
Buildsaclassforeachclassintheassembly,andateststubforeverymethod.
"
%>
2

3
<%
@ImportNameSpace
=
"
System.Reflection
"
%>
4

5
<
scriptrunat
=
"
template
"
>
6

7
private
Assemblyassembly;8

9
public
AssemblyAssemblyToLoad10

{11

get
{returnassembly;}12

set
{assembly=value;}13
}
14

15
</
script
>
然后我们为组建assembly中的每一个类创建一个类,为每一个类创建他的方法。然后直接将模板的输出内容放入Visual Studio.NET,然后在编写组件的单元测试时使用向导。
using
System;2
using
NUnit.Framework;3

4
<%
5
foreach
(TypeT
in
AssemblyToLoad.GetTypes())6

{7
if(T.IsClass)8


{9
%>10

11
[TestFixture]12
publicclass<%=T.Name%>Tests13


{14
<%15
MethodInfo[]methods=T.GetMethods(BindingFlags.Public|BindingFlags.Instance|BindingFlags.Static);16
foreach(MethodInfoMinmethods)17


{18
%>19

20
[Test]21
publicvoid<%=M.Name%>Test22


{23
//TODOWritethistest24
}25
<%26
}27

28
%>}<%29
}30
}
31
%>
/Files/Bear-Study-Hard/AssemblyHelper.zip
首先我们需要创建一个继承UITypeEditor的类。
public
class
AssemblyFilePicker:UITypeEditor2

{3
publicAssemblyFilePicker():base()4


{5
}6
}
关于UITypeEditor的说明请大家参看M<rtx w:st="on">SD</rtx>N或Visual Studio.NET自带帮助中的说明,其中有详细的例子。
然后我们需要重载UITypeEditor类的两个不同的方法。第一个需要重载点的方法是GetEditStyle,这个方法是告诉属性面板对于当前类型是用什么类型的编辑器,在这个例子中我们设置编辑类型为Modal。这样大家可以在该属性格子的右边看到一个小按钮,它将引发一个对话框等模式的对话(trigger a modal dialog)。这是我们的GetEditStyle方法:
public
override
UITypeEditorEditStyleGetEditStyle(ITypeDescriptorContextcontext)2

{3
returnUITypeEditorEditStyle.Modal;4
}
其中的Modal为显示一个省略号按钮。
需要重载的另一个方法是EditValue方法,当用户电击属性时会调用这个方法。按照我们需要加载的组件类型需要创建一个打开文件对话框(open file dialog)然后捕获这个对话框,在属性格子中返回对话框的结果。
public
override
object
EditValue(ITypeDescriptorContextcontext,IServiceProviderprovider,
object
value)2

{3

4
if(provider!=null)5


{
首先我们要从当前的服务和控件中得到一个参考,有了控件的参考我们可以通过它转到ShowDialog方法。(原文:First we need to get a reference to the current service and control, we need the reference to the control so we can pass it to the ShowDialog method.)
IWindowsFormsEditorServiceeditorService
=
(IWindowsFormsEditorService)provider.GetService(
typeof
(IWindowsFormsEditorService));2
ControleditorControl
=
editorService
as
Control;3

4
if
(editorControl
!=
null
)5

{
OpenFileDialogopenFileDialog
=
new
OpenFileDialog();2

3
openFileDialog.CheckFileExists
=
true
;4
openFileDialog.DefaultExt
=
"
.dll
"
;5
openFileDialog.Multiselect
=
false
;6
openFileDialog.Title
=
"
SelectanAssembly:
"
;7
openFileDialog.Filter
=
"
AssemblyFiles|*.dll
"
;
DialogResultresult
=
openFileDialog.ShowDialog(editorControl);
if
(result
==
DialogResult.OK)2

{3
Assemblyassembly=Assembly.LoadFrom(openFileDialog.FileName);4
value=assembly;5
}
6
else
7

{8
value=null;9
}
10
}11
}12

13
return
value;14
}
加载这个模板我们仅需将这个组件assembly与模板放在同一目录下,然后再模板中加入下面两行代码。
<
%@Assembly
Name
="AssemblyHelper"
%
>
2
<
%@Import
NameSpace
="AssemblyHelper"
%
>
然后我们要在组建属性中添加Editor属性,并且指定为UITypeEditor编辑器。
[Editor(
typeof
(AssemblyHelper.AssemblyFilePicker),
typeof
(System.Drawing.Design.UITypeEditor))]2
public
AssemblyAssemblyToLoad3

{4

get
{returnassembly;}5

set
{assembly=value;}6
}
这个模板仅仅可以编译通过,但是由于我们编写显示了一个类型属性面板并不知道如何去操作它,所以我们没有办法自定义指定组件在加载时想要加载的组件。
我们需要创建一个UITypeEditor,这是一个建立属性面板是用的特殊属性的类。UITypeEditor需要创建在一个和模板分离的组件中,我们是用Visual Studio创建这个类。
本文介绍如何为CodeSmith模板创建自定义属性编辑器,包括编写UITypeEditor类及其实现,通过对话框选择组件文件,以及如何将自定义编辑器应用于模板属性。
2521

被折叠的 条评论
为什么被折叠?



