用EasyUi Datagrid展示数据的时候总是要一下这样一段代码

  1. <table id="dt" class="easyui-datagrid">
  2. <thead>
  3. <tr>
  4. <th data-options="field:'Id',width:150,align:'center'">Id</th>
  5. <th data-options="field:'Name',width:150,align:'center'">Name</th>
  6. <th data-options="field:'Category',width:150,align:'center'">Category</th>
  7. <th data-options="field:'Price',width:150,align:'center'">Price</th>
  8. <th data-options="field:'Binary',width:150,align:'center'">Binary</th>
  9. <th data-options="field:'操作',width:80,align:'center',formatter:formatOperate" >操作</th>
  10. </tr>
  11. </thead>
  12. </table>

其实就是对应后台的一个实体类,具体展示就是对于的属性名。我是一个比较懒的人,总是不喜欢做重复性的工作。刚好最近我又量用到EasyUi Datagrid,拷贝了两次这个代码我就烦了,于是想想怎么直接通过实体(ViewModel)来生成对应的easyui datagrid HTML代码。就像MVC带的验证一样,在类上打上自定义的属性,最后在客户端就能实现对应的验证功能。其实就是根据自定义的属性在客户端生成对应的js代码。为了避免反复写html代码这个繁琐的工作,于是我开发了一个简版的datagrid模板生成器。每次只要你想偷懒的时候总是能找到方法。

于是我花了点时间来实现这个想法,并投入到项目中使用。开始没有考虑太多,只是临时满足我现在的需求,以下是主要代码。就是通过反射取出实体的所有字段,然后遍历每个字段,拿到字段上自定义的属性,并挨个处理。根据easyui datagrid模板要求,我们主要是设置table的表头,column每个字段

  1. namespace WebSeat.Web.Core.EasyUi
  2. {
  3. #pragma warning disable 693
  4. public class GenerateDataGrid<T> where T : new()
  5. #pragma warning restore 693
  6. {
  7.  
  8. #region Tools Methods
  9.  
  10. public static IEnumerable<PropertyInfo> GetPropertyInfoList(T entity)
  11. {
  12. return
  13. entity.GetType()
  14. .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase)
  15. .Where(propertyInfo => propertyInfo.Name.ToLower() != "id"); //Id为主键,不能插入。写死了,这个可以做相应修改,主要在字段删改时用到
  16. }
  17.  
  18. public static IEnumerable<PropertyInfo> GetAllPropertyInfoList(T entity)
  19. {
  20. return
  21. entity.GetType()
  22. .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
  23. }
  24.  
  25. #endregion
  26.  
  27. public static string GetDataGridTemplate()
  28. {
  29. return GetDataGridTemplate(new T());
  30. }
  31.  
  32. /// <summary>
  33. /// 生成Datagrid的模板
  34. /// </summary>
  35. /// <param name="entity"></param>
  36. /// <returns></returns>
  37. public static string GetDataGridTemplate(T entity)
  38. {
  39. var sb = new StringBuilder();
  40. //先获取类的Attribute
  41. CustomAttributeData entityType =
  42. typeof(T).CustomAttributes.FirstOrDefault(a => a.AttributeType == typeof(DataOptionsAttribute));
  43.  
  44. #region 对实体的Attibute属性进行处理
  45.  
  46. //类的这个自定义属性不为空
  47. bool isShowNotAttr = true;
  48. string options = string.Empty;
  49. if (entityType != null)
  50. {
  51. if (entityType.NamedArguments != null)
  52. {
  53. foreach (CustomAttributeNamedArgument v in entityType.NamedArguments)
  54. {
  55. if ((String.CompareOrdinal(v.MemberName, "IsShowNotAttr")) == )
  56. {
  57. isShowNotAttr = v.TypedValue.Value is bool && (bool)v.TypedValue.Value;
  58. continue;
  59. }
  60. if ((String.CompareOrdinal(v.MemberName, "Options")) == )
  61. {
  62. options = v.TypedValue.Value as string;
  63. }
  64. }
  65. }
  66. }
  67. options = string.IsNullOrWhiteSpace(options) ? "" : options;
  68.  
  69. #endregion
  70.  
  71. //获取所有类的Property
  72. IEnumerable<PropertyInfo> properties = GetAllPropertyInfoList(entity);
  73.  
  74. //如果设置有不显示没有dataoptions标记的,如果有些字段不显示出来,这个就有作用了。
  75. if (!isShowNotAttr)
  76. {
  77. properties = properties.Where(n => n.CustomAttributes.Any(a => a.AttributeType == typeof(DataOptionsAttribute)));
  78. }
  79. //没有打标记的也要取出来,转换成key-value集合,key是字段名,value是它的GetCustomAttributes。DataOptionsAttribute 自定义属性,见下面代码
  80. Dictionary<string, List<Attribute>> colDicOpts = properties.ToDictionary(property => property.Name,
  81. property =>
  82. {
  83. var list = new List<Attribute>
  84. {
  85. property.GetCustomAttributes(typeof (DataOptionsAttribute), false).FirstOrDefault() as DataOptionsAttribute,
  86. property.GetCustomAttributes(typeof (DisplayAttribute), false).FirstOrDefault() as DisplayAttribute
  87. };
  88. return list;
  89. }
  90. );
            
  91.       //开始拼接,天添加talbe 部分,id和其他的自己可改下代码,做成更灵活的
  92. sb.AppendLine("<table id=\"dt\" class=\"easyui-datagrid\" data-options=\"" + options + "\" > <thead> <tr>");
  93. //挨个遍历 处理,添加 tr
  94. foreach (PropertyInfo pro in properties)
  95. {
  96. //get CustomAttributes
  97. var custAttrs = colDicOpts.SingleOrDefault(n => n.Key == pro.Name);
  98. sb.AppendLine(AppenedTemplate(Template.DataGridTh, custAttrs, pro));
  99. }
  100. sb.AppendLine(@" </tr>
  101. </thead>
  102. </table>");
  103. return sb.ToString();
  104. }
  105.  
  106. private static string AppenedTemplate(string template, KeyValuePair<string, List<Attribute>> attributes, PropertyInfo proinfo = null)
  107. {
  108. var displayName = attributes.Value.SingleOrDefault(n => n is DisplayAttribute) as DisplayAttribute;
  109. //设置字段显示的名称,自己直接设置DisplayAttribute,这个大家肯定很熟悉的属性,如果设置有DisplayAttribute就显示设置的Name否则就是默认字段名称
  110. string str = Template.RegV.Replace(template, displayName != null ? displayName.Name : attributes.Key);
  111. //设置显示的字段field,就是行column显示的字段,这个都是实在字段名,字段名就是key
  112. str = Template.RegF.Replace(str, attributes.Key);
  113. var dataOptions = attributes.Value.SingleOrDefault(n => n is DataOptionsAttribute) as DataOptionsAttribute;
  114. //由于我自己的需要,我要对DateTime类型进行特殊处理
  115. if (proinfo != null && proinfo.PropertyType == typeof(DateTime))
  116. {
  117. //没有自定义dataOptions属性的值
  118. if (dataOptions == null)
  119. {
  120. //WebJs.Format.formatTime 自己的js时间格式化函数
  121. str = Template.RegD.Replace(str, "formatter:WebJs.Format.formatTime");//默认时间格式
  122. }
  123. else
  124. {
  125. str = dataOptions.Options.IndexOf("formatter", StringComparison.CurrentCultureIgnoreCase) >= ?
  126. //已经设置formatter
  127. Template.RegD.Replace(str, dataOptions.Options) :
  128. //默认设置formatter
  129. Template.RegD.Replace(str, dataOptions.Options + "formatter:WebJs.Format.formatTime");
  130. }
  131. }
  132. else
  133. {
  134. //替换data-option 的值, 如果为空就直接替换为空
  135. str = dataOptions == null ?
  136. //把前面的逗号也替换掉
  137. Template.RegDi.Replace(str, string.Empty) :
  138. Template.RegD.Replace(str, dataOptions.Options);
  139. }
  140. return str;
  141. }
  142. }
  143.  
  144. }

DataOptionsAttribute 为自定义属性,Options 的值,到时就直接替换到模板的 data-options里。既是改字段在表头显示的汉字。

  1. namespace WebSeat.Web.Core.Attributes
  2. {
  3. [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false), Serializable]
  4. public class DataOptionsAttribute : Attribute
  5. {
  6. public DataOptionsAttribute()
  7. {
  8. IsShowNotAttr = true;
  9. }
  10. /// <summary>
  11. /// data-options
  12. /// </summary>
  13. public string Options { get; set; }
  14. /// <summary>
  15. /// 是否显示类属性上没有打标记的元素
  16. /// </summary>
  17. public bool IsShowNotAttr { get; set; }
  18. }
  19. }

//模板类

  1. //模板,这里只用到这一部分
    public static class Template
  2. {
  3. public const string DataGridTh = "<th data-options=\"field:'{field}',align:'center',{d}\" > {v}</th>";
  4. public static Regex RegV = new Regex(@"\{v\}");
  5. public static Regex RegF = new Regex(@"\{field\}");
  6. public static Regex RegD = new Regex(@"\{d\}");
  7. public static Regex RegDi = new Regex(@",\{d\}");
  8. }

最后做成HtmlHelper 扩展方法,方便页面调用 ,这里贴出关键代码

  1. namespace WebSeat.Web.Core.Extends
  2. {
  3. public static class ExtendClass
  4. { /// <summary>
  5. /// HtmlHelper扩展方法
  6. /// </summary>
  7. /// <typeparam name="T"></typeparam>
  8. /// <param name="html"></param>
  9. /// <param name="entity"></param>
  10. /// <returns></returns>
  11. public static MvcHtmlString CreateDataGridTemplate<T>(this HtmlHelper html, T entity) where T : new()
  12. {
  13. return new MvcHtmlString(GenerateDataGrid<T>.GetDataGridTemplate(entity));
  14. }
  15. }
  16. }

先是一个基类,然后是一个viewmodel继承基类,注意里面自定义的DataOptions 属性

  1. /// <summary>
  2. /// 模型基类
  3. /// </summary>
  4. public abstract class BaseViewModel
  5. {
  6. /// <summary>
  7. /// ID
  8. /// </summary>
  9. [Display(Name = "主键ID")]
  10. public int Id { get; set; }
  11.  
  12. /// <summary>
  13. /// 添加数据时间
  14. /// </summary>
  15. [Display(Name = "添加数据时间")]
  16. public DateTime CreateTime { get; set; }
  17. }
  18. /// <summary>
  19. /// 班级列表实体
  20. /// </summary>
  21. public class ClassGradeListViewModel : BaseViewModel
  22. {
  23. /// <summary>
  24. /// 班级名称
  25. /// </summary>
  26. [Display(Name = "班级名称")]
  27. public string Name { get; set; }
  28.  
  29. /// <summary>
  30. /// 班级图片地址
  31. /// </summary>
  32. [DataOptions(Options = "ddd:'sdfdsf',xj:'321'")]//对应到列上的data-options 就写到这里,类也是一样
  33. public string PicUrl { get; set; }
  34. }

以下是页面代码,我对easyUi做了一点封装,@Html.CreateDataGridTemplate(new ClassGradeListViewModel())//这句代码生成datagrid 模板

  1. @using WebSeat.FlipCourse.WebApi.ViewModels
  2. @using WebSeat.Web.Core.EasyUi
  3. @using WebSeat.Web.Core.Extends
  4. @{
  5. ViewBag.Title = "LoadClassList";
  6. Layout = "~/Areas/TestApi/Views/Shared/_EasyUiLayout.cshtml";
  7. }
  8.  
  9. @section searchs{
  10. StudentId:<input type="text" id="StudentId" name="StudentId" init="请输入StudentId" class="easyui-numberbox" validtype="isId" />
  11. ClassId:<input type="text" id="ClassId" name="ClassId" value="" init="请输入ClassId" class="easyui-numberbox" validtype="isId" />
  12. <a href="javascript:;"class="easyui-linkbutton" data-options="@IconCls.Search" onclick="LoadClassList()">LoadClassList</a>
  13. }
    //一句话搞定模板生成,再也不用每次写一堆html代码了
  14. @Html.CreateDataGridTemplate(new ClassGradeListViewModel())//这句代码生成datagrid 模板
  15.  
  16. @section scripts{
  17. <script type="text/javascript">
  18. function LoadClassList(opts) {
  19. WebJs.EasyUi.loadpageList('/api/Student/LoadClassList');
  20. }
  21. </script>
  22. }

//对应部分js代码,去掉了很多,大多是根据我们自己的需求来写的

  1. //EasyUi
  2. WebJs.EasyUi = (function () {
  3. //datagrid的默认配置
  4. var defaultOpts = {
  5. collapsible: true,
  6. rownumbers: true,
  7. singleSelect: true,
  8. pagination: true,
  9. striped: true,
  10. fit: true,
  11. border: false,
  12. method: 'get',
  13. toolbar: "#Search",
  14. idField: 'Id',
  15. pageSize: 10,
  16. pageNumber: 1,
  17. headers: {
  18. "contentType": "application/json; charset=utf-8",
  19. "token": WebJs.Utils.GetCookie('Token') || "token"
  20. },
  21. loadFilter: filterData,
  22. reloadFunc: function () { return false; },
  23. onLoadError: WebJs.Common.ShowErrors
  24. },
  25. loadTimmer, //记录 timmer防止反复加载
  26. loadTime = 0, //多少毫秒加载一次
  27. accordion = '#aa',
  28. tabId = '#tabs',
  29. layOutId = '#body',
  30. dtId = '#dt';
  31. //取得Id
  32. function getdg(id) { //取得datagrid的Id 默认为 dt,
  33. id = id || dtId;
  34. return $(id);
  35. }
  36. //扩展EasyUI的验证
  37. function extendEasyUiValidate() {
  38. $.extend($.fn.validatebox.defaults.rules, {
  39. pattern: {
  40. validator: function (value, param) {
  41. var re = new RegExp('' + param[0], 'gi');
  42. //if (param[1]) { msg = param[1]; }
  43. //WebJs.Dialog.Tip(param[0] +param[1]+ "===" + value + "---" + re.test(value));
  44. return re.test(value);
  45. },
  46. message: '输入格式不正确'
  47. },
  48. maxLength: {
  49. validator: function (value, param) {
  50. return value.trim().length <= param[0];
  51. },
  52. message: '最多只能输入{0}个字符'
  53. },
  54. list: {
  55. validator: function (value, param) {
  56. return /^\d[\d|,?]*/gi.test(value);
  57. },
  58. message: '输入格式不对,数字之间都好隔开'
  59. },
  60. isId: {
  61. validator: function (value, param) {
  62. return /^[1-9]\d*$/gi.test(value) && ((value | 0) > 0 && (value | 0) < 2e6);
  63. },
  64. message: 'Id必须是数字,类型为int'
  65. },
  66. equalTo: {
  67. validator: function (value, param) {
  68. return value == $(param[0]).val();
  69. },
  70. message: '两次输入的字符不一至'
  71. },
  72. number: {
  73. validator: function (value, param) {
  74. return /^\d+$/.test(value);
  75. },
  76. message: '请输入数字'
  77. }
  78. });
  79. }
  80. //专为我们自己的分页而生
  81. function loadpageList(url, id) {
  82. var form = $('#SearchForm');
  83. if (form.children().length && !form.form('validate')) {
  84. return;
  85. }
  86. var para = new BaseParams(),//和后台分页实体对应
  87. formjson = form.serializeJson(),//serializeJson 需要自己扩展
  88. params = $.extend(para, formjson),cfgs = {
  89. method: 'post',
  90. queryParams: params
  91. };
  92. //设置datagrid的分页参数
  93. cfgs.pageSize = params.PageSize || 10;
  94. cfgs.pageNumber = params.PageIndex || 1;
  95. WebJs.EasyUi.LoadData(url,cfgs,id);
  96. }
  97. return {
  98. //加载datagrid的数据
  99. LoadData: function (url, opts, id) {
  100. //clearTimeout(loadTimmer);
  101. var defaults = $.extend(defaultOpts, opts || {});
  102. url && (defaults.url = url);
  103. //loadTimmer = setTimeout(function () {
  104. //可以对datagrid进行缓存
  105. getdg(id).datagrid(defaults);
  106. //}, loadTime);
  107. },
  108. //加载分页数据
  109. loadpageList: loadpageList,
  110. filterData: filterData
  111. };
  112. })();

//最终页面效果, 生成的datagrid模板

调用一句话就生成datagrid模板,这个不适合复杂的模板。

我暂时就想到这些,这样可以在项目组偷个懒。

其实项目中很多地方都可以这样,只要有想法自己就去做,不管做的好还是差,做成功还是有点小成就感。

做完这个东西并且在项目中实际运用,最后效果良好,各种好使,当然后来也有很多改动。

反射实体自动生成EasyUi DataGrid模板的更多相关文章

  1. 反射实体自动生成EasyUi DataGrid模板 第二版--附项目源码

    之前写过一篇文章,地址 http://www.cnblogs.com/Bond/p/3469798.html   大概说了下怎么通过反射来自动生成对应EasyUi datagrid的模板,然后贴了很多 ...

  2. Pycharm 设置python文件自动生成头部信息模板

    设置头部信息路径: 打开File—Settings—Editor—File and Code Templates—Python Script 输入要自动生成的头部信息模板 这样,新建py文件就会自动生 ...

  3. sqlite3 根据实体自动生成建表语句

      public class BuildSqlTool { public static string GetCreateTableSql(object t) { //CREATE TABLE &quo ...

  4. C#——反射,自动生成添加的SQL语句

    C#中的反射.是C#中特别重要也是特别神奇的特性,对后面学习框架,了解框架的原理.以及自己写框架,都是必不可少的.学习反射的过程中.总给我一种茅塞顿开的感觉,以前不懂的,现在懂了 反射的介绍:http ...

  5. IDEA自动生成的注释模板

    使用效果如下: * * @功能描述 : $params$ * @return $returns$ * @author xuetao */ 其中 $params$的表达式如下: groovyScript ...

  6. quartus II 自动生成testbench

    如果自己不想写这些testbench的这些固定格式,可以在quartus里自动生成testbench文件的模板,然后往里面写信号就行了 步骤:processing->start->star ...

  7. Vs code自动生成Doxygen格式注释

    前言 ​ 程序中注释的规范和统一性的重要性不言而喻,本文就推荐一种在用vscode编写代码时自动化生成标准化注释格式的方法,关于Doxygen规范及其使用可查看博文 代码注释规范之Doxygen. ​ ...

  8. T4 模板自动生成带注释的实体类文件

    T4 模板自动生成带注释的实体类文件 - 只需要一个 SqlSugar.dll 生成实体就是这么简单,只要建一个T4文件和 文件夹里面放一个DLL. 使用T4模板教程 步骤1 创建T4模板 如果你没有 ...

  9. codesmith 自动生成C# model 实体模板

    <%-- Name:自动生成 Author: 陈胜威 Description: 直接生成model类 --%> <%@ Template Language="C#" ...

随机推荐

  1. Android开发之处理崩溃异常

    众所周知,android的设备千差万别,难免会发生崩溃异常等现象,这个时候就需要捕获哪些崩溃异常了,也就是捕获崩溃异常的相关信息,并记录下来,这样一来方便开发人员和测试人员的分析与调试. 1.首先我们 ...

  2. 文件处理-Directory类 (C#)

    转http://skybirdzw.blog.163.com/blog/static/7257062620099751329403/ 文件处理-Directory类 (C#) Directory.Cr ...

  3. VB学习笔记

    stack segment stack 'stack' dw dup() ;此处输入堆栈段代码 stack ends data segment ;IBUF OBUF 看成是内存的地址,IBUF+1和I ...

  4. Form开发中组件控制的几个常用方法

    转自:http://oracleseeker.com/2009/09/01/graphical_component_control_in_oracle_ebs_form/ 在Oracle EBS 的F ...

  5. c语言,strcmp(),字符串比较,看Asic 码,str1>str2,返回值 > 0;两串相等,返回

    #include<stdio.h> #include<string.h> int main() {  char *buffer1="aaa",*buffer ...

  6. Unity3D 之3D游戏角色控制器运动

    3D运动,绑定了人形控制器后的一个简单的运动方法. using UnityEngine; using System.Collections; public class PlayerMove : Mon ...

  7. 怎么用js代码改变单选框的选中状态

    今天突然有一个需求要用到,使用js代码改变单选框的选中状态.当时想也不想直接 function doGender(gender) { if (gender == "男") { ge ...

  8. MVC小系列(十)【PartialView中的页面重定向】

    在mvc的每个Action中,都可以指定一种返回页面的类型,可以是ActionResult,这表示返回的页面为View或者是一个PartialView, 在以Aspx为页面引擎时,PartialVie ...

  9. editActionsForRowAtIndexPath(iOS8) tableview编辑(删除、插入、移动)

    ios8 出来的左滑小菜单 可以自定义想要的按钮 (要求ios8以上) - (nullable NSArray<UITableViewRowAction *> *)tableView:(U ...

  10. 销毁session

    session运行在服务器是单用户,每个session都有一个唯一的sessionid 用法:session.setAttribute("userName", "张三丰& ...