编写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.)

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

 1<%@ CodeTemplate Language="C#" TargetLanguage="C#" Description="Builds a class for each class in the assembly, and a test stub for every method." %>
 2
 3<%@ Import NameSpace="System.Reflection" %>
 4
 5<script runat="template">
 6
 7private Assembly assembly;
 8
 9public Assembly AssemblyToLoad
10{
11      get{return assembly;}
12      set{assembly = value;}
13}
14
15</script>

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

 1using System;
 2using NUnit.Framework;
 3
 4<%
 5      foreach(Type T in AssemblyToLoad.GetTypes())
 6      {
 7            if(T.IsClass)
 8            {
 9                  %>
10
11                  [TestFixture]
12                  public class <%=T.Name%>Tests
13                  {
14                  <%
15                              MethodInfo[] methods = T.GetMethods ( BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static  );
16                              foreach(MethodInfo M in methods)
17                              {
18                                    %>
19
20                                    [Test]
21                                    public void <%=M.Name%>Test
22                                    {
23                                          //TODO Write this test
24                                    }                 
25                                    <%
26                              }
27
28                  %>}<%
29            }
30      }
31%>

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

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

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

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

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

关于UITypeEditor的说明请大家参看M<?xml:namespace prefix = st1 />SDN或Visual Studio.NET自带帮助中的说明,其中有详细的例子。

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

1public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) 
2{
3      return UITypeEditorEditStyle.Modal;
4}

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

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

1public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, 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.)

1IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
2Control editorControl = editorService as Control;
3
4if (editorControl != null) 
5{

然后我们创建一个openFileDialog类并填入适合的属性。

1OpenFileDialog openFileDialog = new OpenFileDialog();                         
2
3openFileDialog.CheckFileExists = true;
4openFileDialog.DefaultExt = ".dll";
5openFileDialog.Multiselect = false;
6openFileDialog.Title = "Select an Assembly:";
7openFileDialog.Filter = "Assembly Files | *.dll";

然后我们通过控件的参考(reference)将对话框显示给用户。

1DialogResult result = openFileDialog.ShowDialog(editorControl);

下一步我们检查用户是否点击了OK按钮,如果点击了,通过文件选择对话框选择文件后使用LoadForm方法加载这个组件,最后返回这个值。

 1if (result == DialogResult.OK)
 2            {
 3Assembly assembly = Assembly.LoadFrom( openFileDialog.FileName ) ;
 4                  value = assembly; 
 5            }
 6            else
 7            {
 8                  value = null;
 9            }
10      }
11}
12
13return value;
14}

这个值将被放在属性面板中并可以被模板读取,但是需要注意,在我们作这个之前要将组件import引入到模板中,并在模板中用一对属性声明。

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

1<%@ Assembly Name="AssemblyHelper" %>
2<%@ Import NameSpace="AssemblyHelper" %>

然后我们要在组建属性中添加Editor属性,并且指定为UITypeEditor编辑器。

1[Editor(typeof(AssemblyHelper.AssemblyFilePicker), typeof(System.Drawing.Design.UITypeEditor))]
2public Assembly AssemblyToLoad
3{
4      get{return assembly;}
5      set{assembly = value;}
6}

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

转载于:https://www.cnblogs.com/jirong/archive/2006/04/13/374443.html

CodeSmith基础(八)相关推荐

  1. CodeSmith基础教程

    请大家耐心看完所有的基础文章,前两篇网上发表的比较多,是CodeSmith英文帮助文档的第一篇,我后面写的基础是将其他所有的英文帮助全部翻译出来了,全部为本人手写翻译,希望对大家有所帮助 一.第一个模 ...

  2. css3制作八棱锥_CSS基础八部分-第二部分

    emmet语法 1.简介 Emmet语法的前身是Zen coding,它使用缩写,来提高html/css的编写速度, Vscode内部已经集成该语法. 2.快速生成HTML结构语法 生成标签 直接输入 ...

  3. C++学习基础八——重载输入和输出操作符

    C++学习基础八--重载输入和输出操作符 一.重载输入操作符的要点: 1.返回值为istream &. 2.第一个参数为istream &in. 3.第二个参数为自定义类型的引用对象( ...

  4. Socket基础八:网络IO模型的应用

    Socket基础八:网络IO模型的应用 作者:刘磊 2020.4.27 参考书目:<Windows网络编程>刘琰等著 一.实验目的 1)掌握WindowsI/O操作的基本原理. 2)掌握阻 ...

  5. JavaScript 入门基础 (八)

    目录 1.JavaScript概述 2.HTML世界 3.JavaScript基本语法 4.JavaScript语句 5.JavaScript内置对象 6.Document对象 7.window和fr ...

  6. CodeSmith基础(七)

    本文翻译的内容为CodeSmith控制台指南. 很多人仅仅知道CodeSmith像一个图形应用程序,或者可能是一个Visual Studio的附件,但是通过CodeSmith的控制台应用程序还有好多其 ...

  7. CodeSmith 基础用法和例子

    〇.            前言 一.            工具设置 CodeSmith默认是不支持中文的,那么我们必须要先设置使其支持中文显示,保存.并且要能够在生成文件中支持中文. [Tools ...

  8. CodeSmith基础(二)

            本文将介绍CodeSmith与数据库进行交互生成相应的存储过程,本例使用的数据库为SQL Server 2000.         在与数据库进行交互时,我们使用到了一个CodeSmi ...

  9. JAVA知识基础(八):继承

    1.概述 1.1.继承的由来 至于由来简单一句话:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为. 继承描述的是事物之间的所属关系,这种关系是 is-a ...

最新文章

  1. 分布式存储系统考虑因素-一致性
  2. 重构代码(应如写诗)
  3. android:layout_weight的真实含义
  4. 小米视频加载进度条效果实现
  5. request body 里丢东西了_26. Scrapy 框架-模拟登录-Request、Response
  6. linux职业_对Linux的好奇心导致了意外的职业
  7. 高仿小红书引导页实现效果
  8. ps-色彩饱和度的设计
  9. Linux 命令(106)—— chkconfig 命令
  10. python入门学习(五 字符串string和变量variable)
  11. spark sql python_Spark 3.0开发近两年终于发布,流、Python、SQL重大更新详解
  12. 【经典递归问题 汉诺塔 求解】
  13. 《期权、期货及其他衍生产品》读书笔记(第二章:期货市场与中央交易对手)
  14. Excel单元格自定义数值格式详细测试整理 及 Python用openpyxl设置Excel单元格属性——数值格式
  15. 第六章 商品详情进阶 + redis分布式锁 + redis问题解决 + redisson + 布隆过滤器
  16. Apache2.4的安装、配置与常见的问题(Windows)
  17. S3D 2.0 截图
  18. 修改服务器端数据库,问道1.6 开区 服务器环境配置 数据库修改 服务端启动教程...
  19. 彻底征服 React.js + Flux + Redux【讲师辅导】-曾亮-专题视频课程
  20. 阿里云手动更新dns解析

热门文章

  1. 是以微型计算机为中心 配以相应的外围设备,______是以微型计算机为中心,配以相应的外围设备、电源和辅助电路,以及指挥微型计算机工作的系统软件而构成的。...
  2. ?php if ($modules) { ?,phpStudy安装鲶鱼CMS怎样开启伪静态
  3. mysql索引数据结构图解_干货:mysql索引的数据结构
  4. python记录输入次数_如何计算用户输入错误的次数
  5. velocity(vm)模板引擎学习介绍及语法
  6. Linux在线升级ruby
  7. dorado 刷新_dorado BDF常见问题
  8. java redis 原子操作_redis快速入门
  9. 系统学习机器学习之神经网络(四) --SOM
  10. DSP之时钟与定时器之一时钟发生器