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

<table id="dt" class="easyui-datagrid">
<thead>
<tr>
<th data-options="field:'Id',width:150,align:'center'">Id</th>
<th data-options="field:'Name',width:150,align:'center'">Name</th>
<th data-options="field:'Category',width:150,align:'center'">Category</th>
<th data-options="field:'Price',width:150,align:'center'">Price</th>
<th data-options="field:'Binary',width:150,align:'center'">Binary</th>
<th data-options="field:'操作',width:80,align:'center',formatter:formatOperate" >操作</th>
</tr>
</thead>
</table>

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

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

namespace WebSeat.Web.Core.EasyUi
{
#pragma warning disable 693
public class GenerateDataGrid<T> where T : new()
#pragma warning restore 693
{ #region Tools Methods public static IEnumerable<PropertyInfo> GetPropertyInfoList(T entity)
{
return
entity.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase)
.Where(propertyInfo => propertyInfo.Name.ToLower() != "id"); //Id为主键,不能插入。写死了,这个可以做相应修改,主要在字段删改时用到
} public static IEnumerable<PropertyInfo> GetAllPropertyInfoList(T entity)
{
return
entity.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
} #endregion public static string GetDataGridTemplate()
{
return GetDataGridTemplate(new T());
} /// <summary>
/// 生成Datagrid的模板
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public static string GetDataGridTemplate(T entity)
{
var sb = new StringBuilder();
//先获取类的Attribute
CustomAttributeData entityType =
typeof(T).CustomAttributes.FirstOrDefault(a => a.AttributeType == typeof(DataOptionsAttribute)); #region 对实体的Attibute属性进行处理 //类的这个自定义属性不为空
bool isShowNotAttr = true;
string options = string.Empty;
if (entityType != null)
{
if (entityType.NamedArguments != null)
{
foreach (CustomAttributeNamedArgument v in entityType.NamedArguments)
{
if ((String.CompareOrdinal(v.MemberName, "IsShowNotAttr")) == )
{
isShowNotAttr = v.TypedValue.Value is bool && (bool)v.TypedValue.Value;
continue;
}
if ((String.CompareOrdinal(v.MemberName, "Options")) == )
{
options = v.TypedValue.Value as string;
}
}
}
}
options = string.IsNullOrWhiteSpace(options) ? "" : options; #endregion //获取所有类的Property
IEnumerable<PropertyInfo> properties = GetAllPropertyInfoList(entity); //如果设置有不显示没有dataoptions标记的,如果有些字段不显示出来,这个就有作用了。
if (!isShowNotAttr)
{
properties = properties.Where(n => n.CustomAttributes.Any(a => a.AttributeType == typeof(DataOptionsAttribute)));
}
//没有打标记的也要取出来,转换成key-value集合,key是字段名,value是它的GetCustomAttributes。DataOptionsAttribute 自定义属性,见下面代码
Dictionary<string, List<Attribute>> colDicOpts = properties.ToDictionary(property => property.Name,
property =>
{
var list = new List<Attribute>
{
property.GetCustomAttributes(typeof (DataOptionsAttribute), false).FirstOrDefault() as DataOptionsAttribute,
property.GetCustomAttributes(typeof (DisplayAttribute), false).FirstOrDefault() as DisplayAttribute
};
return list;
}
);
        
      //开始拼接,天添加talbe 部分,id和其他的自己可改下代码,做成更灵活的
sb.AppendLine("<table id=\"dt\" class=\"easyui-datagrid\" data-options=\"" + options + "\" > <thead> <tr>");
//挨个遍历 处理,添加 tr
foreach (PropertyInfo pro in properties)
{
//get CustomAttributes
var custAttrs = colDicOpts.SingleOrDefault(n => n.Key == pro.Name);
sb.AppendLine(AppenedTemplate(Template.DataGridTh, custAttrs, pro));
}
sb.AppendLine(@" </tr>
</thead>
</table>");
return sb.ToString();
} private static string AppenedTemplate(string template, KeyValuePair<string, List<Attribute>> attributes, PropertyInfo proinfo = null)
{
var displayName = attributes.Value.SingleOrDefault(n => n is DisplayAttribute) as DisplayAttribute;
//设置字段显示的名称,自己直接设置DisplayAttribute,这个大家肯定很熟悉的属性,如果设置有DisplayAttribute就显示设置的Name否则就是默认字段名称
string str = Template.RegV.Replace(template, displayName != null ? displayName.Name : attributes.Key);
//设置显示的字段field,就是行column显示的字段,这个都是实在字段名,字段名就是key
str = Template.RegF.Replace(str, attributes.Key);
var dataOptions = attributes.Value.SingleOrDefault(n => n is DataOptionsAttribute) as DataOptionsAttribute;
//由于我自己的需要,我要对DateTime类型进行特殊处理
if (proinfo != null && proinfo.PropertyType == typeof(DateTime))
{
//没有自定义dataOptions属性的值
if (dataOptions == null)
{
//WebJs.Format.formatTime 自己的js时间格式化函数
str = Template.RegD.Replace(str, "formatter:WebJs.Format.formatTime");//默认时间格式
}
else
{
str = dataOptions.Options.IndexOf("formatter", StringComparison.CurrentCultureIgnoreCase) >= ?
//已经设置formatter
Template.RegD.Replace(str, dataOptions.Options) :
//默认设置formatter
Template.RegD.Replace(str, dataOptions.Options + "formatter:WebJs.Format.formatTime");
}
}
else
{
//替换data-option 的值, 如果为空就直接替换为空
str = dataOptions == null ?
//把前面的逗号也替换掉
Template.RegDi.Replace(str, string.Empty) :
Template.RegD.Replace(str, dataOptions.Options);
}
return str;
}
} }

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

namespace WebSeat.Web.Core.Attributes
{
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false), Serializable]
public class DataOptionsAttribute : Attribute
{
public DataOptionsAttribute()
{
IsShowNotAttr = true;
}
/// <summary>
/// data-options
/// </summary>
public string Options { get; set; }
/// <summary>
/// 是否显示类属性上没有打标记的元素
/// </summary>
public bool IsShowNotAttr { get; set; }
}
}

//模板类

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

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

namespace WebSeat.Web.Core.Extends
{
public static class ExtendClass
{ /// <summary>
/// HtmlHelper扩展方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="html"></param>
/// <param name="entity"></param>
/// <returns></returns>
public static MvcHtmlString CreateDataGridTemplate<T>(this HtmlHelper html, T entity) where T : new()
{
return new MvcHtmlString(GenerateDataGrid<T>.GetDataGridTemplate(entity));
}
}
}

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

    /// <summary>
/// 模型基类
/// </summary>
public abstract class BaseViewModel
{
/// <summary>
/// ID
/// </summary>
[Display(Name = "主键ID")]
public int Id { get; set; } /// <summary>
/// 添加数据时间
/// </summary>
[Display(Name = "添加数据时间")]
public DateTime CreateTime { get; set; }
}
/// <summary>
/// 班级列表实体
/// </summary>
public class ClassGradeListViewModel : BaseViewModel
{
/// <summary>
/// 班级名称
/// </summary>
[Display(Name = "班级名称")]
public string Name { get; set; } /// <summary>
/// 班级图片地址
/// </summary>
[DataOptions(Options = "ddd:'sdfdsf',xj:'321'")]//对应到列上的data-options 就写到这里,类也是一样
public string PicUrl { get; set; }
}

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

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

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

//EasyUi
WebJs.EasyUi = (function () {
//datagrid的默认配置
var defaultOpts = {
collapsible: true,
rownumbers: true,
singleSelect: true,
pagination: true,
striped: true,
fit: true,
border: false,
method: 'get',
toolbar: "#Search",
idField: 'Id',
pageSize: 10,
pageNumber: 1,
headers: {
"contentType": "application/json; charset=utf-8",
"token": WebJs.Utils.GetCookie('Token') || "token"
},
loadFilter: filterData,
reloadFunc: function () { return false; },
onLoadError: WebJs.Common.ShowErrors
},
loadTimmer, //记录 timmer防止反复加载
loadTime = 0, //多少毫秒加载一次
accordion = '#aa',
tabId = '#tabs',
layOutId = '#body',
dtId = '#dt';
//取得Id
function getdg(id) { //取得datagrid的Id 默认为 dt,
id = id || dtId;
return $(id);
}
//扩展EasyUI的验证
function extendEasyUiValidate() {
$.extend($.fn.validatebox.defaults.rules, {
pattern: {
validator: function (value, param) {
var re = new RegExp('' + param[0], 'gi');
//if (param[1]) { msg = param[1]; }
//WebJs.Dialog.Tip(param[0] +param[1]+ "===" + value + "---" + re.test(value));
return re.test(value);
},
message: '输入格式不正确'
},
maxLength: {
validator: function (value, param) {
return value.trim().length <= param[0];
},
message: '最多只能输入{0}个字符'
},
list: {
validator: function (value, param) {
return /^\d[\d|,?]*/gi.test(value);
},
message: '输入格式不对,数字之间都好隔开'
},
isId: {
validator: function (value, param) {
return /^[1-9]\d*$/gi.test(value) && ((value | 0) > 0 && (value | 0) < 2e6);
},
message: 'Id必须是数字,类型为int'
},
equalTo: {
validator: function (value, param) {
return value == $(param[0]).val();
},
message: '两次输入的字符不一至'
},
number: {
validator: function (value, param) {
return /^\d+$/.test(value);
},
message: '请输入数字'
}
});
}
//专为我们自己的分页而生
function loadpageList(url, id) {
var form = $('#SearchForm');
if (form.children().length && !form.form('validate')) {
return;
}
var para = new BaseParams(),//和后台分页实体对应
formjson = form.serializeJson(),//serializeJson 需要自己扩展
params = $.extend(para, formjson),cfgs = {
method: 'post',
queryParams: params
};
//设置datagrid的分页参数
cfgs.pageSize = params.PageSize || 10;
cfgs.pageNumber = params.PageIndex || 1;
WebJs.EasyUi.LoadData(url,cfgs,id);
}
return {
//加载datagrid的数据
LoadData: function (url, opts, id) {
//clearTimeout(loadTimmer);
var defaults = $.extend(defaultOpts, opts || {});
url && (defaults.url = url);
//loadTimmer = setTimeout(function () {
//可以对datagrid进行缓存
getdg(id).datagrid(defaults);
//}, loadTime);
},
//加载分页数据
loadpageList: loadpageList,
filterData: filterData
};
})();

//最终页面效果, 生成的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. html笔记04:在html之中导入css两种常见方法

    1.导入式: <html> <head> <title></title> <style type="text/css"> ...

  2. 深入理解计算机系统第二版习题解答CSAPP 2.8

    给出位微量的布尔去处的求值结果. 运算 结果 a 0110 1001 b 0101 0101     ~a 1001 0110 ~b 1010 1010     a&b 0100 0001 a ...

  3. java基础语法笔记

    这段时间看了一些java,急了一些笔记,记下一遍以后复习用! 2016-07-24 15:12:40 java很多语法都跟C#类似,下面列举一些不同的地方******注意***** java中的系统方 ...

  4. HDU-1031(水题)

    Design T-Shirt Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) P ...

  5. jquery无法读取json文件问题

    jquery无法读取json文件,如:user.json文件无法读取.把user.json文件的后缀名修改为aspx,文件内容不变,则可以读取~ 原理不懂!~~

  6. 20160420javaweb之文件上传和下载

    一.文件上传 1.提供表单允许用户通过表单选择文件进行上传 表单必须是POST提交 文件输入框必须有name属性,只有有name属性的输入项浏览器才会进行提交 需要设置enctype属性值为multi ...

  7. PIMP模式的理解

    看了[C++程序设计技巧]Pimpl机制 之后,想了半天才理解    // MyClass.h 2: class MyClassImpl; // forward declaration 3: clas ...

  8. UVA 11078 Open Credit System(扫描 维护最大值)

    Open Credit System In an open credit system, the students can choose any course they like, but there ...

  9. Codevs 3731 寻找道路 2014年 NOIP全国联赛提高组

    3731 寻找道路 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找 ...

  10. Qt 操作Excel

    Qt对Excel的数据读/写操作没有现存的类,需要使用QAxObject,下面是从网上下载下来的一个封装好的类,感觉还可以,一般情况下够用,拿来给大家分享. 头文件: #ifndef EXCELENG ...