CodeSmith基础(八)

CodeSmith基础(八)

编写CodeSmith自定义属性的编辑器(Writing Custom Property Editors

当你开始编写自定义的CodeSmith模板时,很可能对于使用它的stringsintegers属性很满意,但有时你会发现需要创建一个不同类型的属性,可能是一个自定义的类型或者是.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.

首先,我们来关注一下模板的组件属性,暂且不看自定义编写的代码。模板的第一部分是一些声明定义和属性。将属性放在脚本标签中代替使用属性声明,在下一部分将看到这样做的必要。

1 <% @CodeTemplateLanguage = " C# " TargetLanguage = " C# " Description = " Buildsaclassforeachclassintheassembly,andateststubforeverymethod. " %>
2
3 <% @ImportNameSpace = " System.Reflection " %>
4
5 < scriptrunat = " template " >
6
7 private Assemblyassembly;
8
9 public AssemblyAssemblyToLoad
10 {
11get{returnassembly;}
12set{assembly=value;}
13}

14
15 </ script >

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

1 using System;
2 using NUnit.Framework;
3
4 <%
5 foreach (TypeT in AssemblyToLoad.GetTypes())
6 {
7if(T.IsClass)
8{
9%>
10
11[TestFixture]
12publicclass<%=T.Name%>Tests
13{
14<%
15MethodInfo[]methods=T.GetMethods(BindingFlags.Public|BindingFlags.Instance|BindingFlags.Static);
16foreach(MethodInfoMinmethods)
17{
18%>
19
20[Test]
21publicvoid<%=M.Name%>Test
22{
23//TODOWritethistest
24}

25<%
26}

27
28%>}
<%
29}

30}

31 %>

/Files/Bear-Study-Hard/AssemblyHelper.zip

首先我们需要创建一个继承UITypeEditor的类。

1 public class AssemblyFilePicker:UITypeEditor
2 {
3publicAssemblyFilePicker():base()
4{
5}

6}

关于UITypeEditor的说明请大家参看M<rtx w:st="on">SD</rtx>NVisual Studio.NET自带帮助中的说明,其中有详细的例子。

然后我们需要重载UITypeEditor类的两个不同的方法。第一个需要重载点的方法是GetEditStyle,这个方法是告诉属性面板对于当前类型是用什么类型的编辑器,在这个例子中我们设置编辑类型为Modal。这样大家可以在该属性格子的右边看到一个小按钮,它将引发一个对话框等模式的对话(trigger a modal dialog)。这是我们的GetEditStyle方法:

1 public override UITypeEditorEditStyleGetEditStyle(ITypeDescriptorContextcontext)
2 {
3returnUITypeEditorEditStyle.Modal;
4}

其中的Modal为显示一个省略号按钮。

需要重载的另一个方法是EditValue方法,当用户电击属性时会调用这个方法。按照我们需要加载的组件类型需要创建一个打开文件对话框(open file dialog)然后捕获这个对话框,在属性格子中返回对话框的结果。

1 public override object EditValue(ITypeDescriptorContextcontext,IServiceProviderprovider, object value)
2 {
3
4if(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.
1 IWindowsFormsEditorServiceeditorService = (IWindowsFormsEditorService)provider.GetService( typeof (IWindowsFormsEditorService));
2 ControleditorControl = editorService as Control;
3
4 if (editorControl != null )
5 {

1 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 " ;

1 DialogResultresult = openFileDialog.ShowDialog(editorControl);

1 if (result == DialogResult.OK)
2 {
3Assemblyassembly=Assembly.LoadFrom(openFileDialog.FileName);
4value=assembly;
5}

6 else
7 {
8value=null;
9}

10 }
11 }
12
13 return value;
14 }

加载这个模板我们仅需将这个组件assembly与模板放在同一目录下,然后再模板中加入下面两行代码。

1 < %@Assembly Name ="AssemblyHelper" % >
2 < %@Import NameSpace ="AssemblyHelper" % >
然后我们创建一个openFileDialog类并填入适合的属性。 然后我们通过控件的参考(reference)将对话框显示给用户。 下一步我们检查用户是否点击了OK按钮,如果点击了,通过文件选择对话框选择文件后使用LoadForm方法加载这个组件,最后返回这个值。 这个值将被放在属性面板中并可以被模板读取,但是需要注意,在我们作这个之前要将组件import引入到模板中,并在模板中用一对属性声明。

然后我们要在组建属性中添加Editor属性,并且指定为UITypeEditor编辑器。
1 [Editor( typeof (AssemblyHelper.AssemblyFilePicker), typeof (System.Drawing.Design.UITypeEditor))]
2 public AssemblyAssemblyToLoad
3 {
4get{returnassembly;}
5set{assembly=value;}
6}

当属性面板读取到这些属性时,它将使用我们自定义的UITypeEditor编辑器并允许用户从打开文件对话框中选择一个组件。

这个模板仅仅可以编译通过,但是由于我们编写显示了一个类型属性面板并不知道如何去操作它,所以我们没有办法自定义指定组件在加载时想要加载的组件。

我们需要创建一个UITypeEditor,这是一个建立属性面板是用的特殊属性的类。UITypeEditor需要创建在一个和模板分离的组件中,我们是用Visual Studio创建这个类。

你可能感兴趣的:(.net,单元测试,脚本)