反射实体自动生成EasyUi DataGrid模板
用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模板的更多相关文章
- 反射实体自动生成EasyUi DataGrid模板 第二版--附项目源码
之前写过一篇文章,地址 http://www.cnblogs.com/Bond/p/3469798.html 大概说了下怎么通过反射来自动生成对应EasyUi datagrid的模板,然后贴了很多 ...
- Pycharm 设置python文件自动生成头部信息模板
设置头部信息路径: 打开File—Settings—Editor—File and Code Templates—Python Script 输入要自动生成的头部信息模板 这样,新建py文件就会自动生 ...
- sqlite3 根据实体自动生成建表语句
public class BuildSqlTool { public static string GetCreateTableSql(object t) { //CREATE TABLE &quo ...
- C#——反射,自动生成添加的SQL语句
C#中的反射.是C#中特别重要也是特别神奇的特性,对后面学习框架,了解框架的原理.以及自己写框架,都是必不可少的.学习反射的过程中.总给我一种茅塞顿开的感觉,以前不懂的,现在懂了 反射的介绍:http ...
- IDEA自动生成的注释模板
使用效果如下: * * @功能描述 : $params$ * @return $returns$ * @author xuetao */ 其中 $params$的表达式如下: groovyScript ...
- quartus II 自动生成testbench
如果自己不想写这些testbench的这些固定格式,可以在quartus里自动生成testbench文件的模板,然后往里面写信号就行了 步骤:processing->start->star ...
- Vs code自动生成Doxygen格式注释
前言 程序中注释的规范和统一性的重要性不言而喻,本文就推荐一种在用vscode编写代码时自动化生成标准化注释格式的方法,关于Doxygen规范及其使用可查看博文 代码注释规范之Doxygen. ...
- T4 模板自动生成带注释的实体类文件
T4 模板自动生成带注释的实体类文件 - 只需要一个 SqlSugar.dll 生成实体就是这么简单,只要建一个T4文件和 文件夹里面放一个DLL. 使用T4模板教程 步骤1 创建T4模板 如果你没有 ...
- codesmith 自动生成C# model 实体模板
<%-- Name:自动生成 Author: 陈胜威 Description: 直接生成model类 --%> <%@ Template Language="C#" ...
随机推荐
- GCC安装
1.apt-get install gcc2.apt-get install make3.apt-get install gdb apt-get install build-essential 这个 ...
- JAVA的instanceOf什么时候用啊
当你拿到一个对象的引用时(例如参数),你可能需要判断这个引用真正指向的类.所以你需要从该类继承树的最底层开始, 使用instanceof操作符判断,第一个结果为true的类即为引用真正指向的类. cl ...
- MVC小系列(七)【分部视图中的POST】
MVC小系列(七)[分部视图中的POST] 在PartialView中进行表单提交的作用:1 这个表单不止一个地方用到,2 可能涉及到异步的提交问题 这两种情况都可能需要把表单建立在分部视图上, 使用 ...
- 使用PDO持久化连接
无论是何种编程语言,几乎都要经常与各种数据库打交道.不过,众所周知的是,在程序与数据库之间建立连接是一件比较耗费资源的事情,因此编程技术领域的许多专家.前辈们就设想并提出了各种解决方案,以减少不必要的 ...
- php模板引擎
http://baike.baidu.com/link?url=HmXfdJBv3zpCdnZPeaSmZmqDBHlyTBnz9Rmb5it-jf1_NLHfaku6_i8ssUYbnaTQEBD4 ...
- ios Toll-Free Bridging
有一些数据类型是能够在 Core Foundation Framework 和 Foundation Framework 之间交换使用的.这意味着,对于同一个数据类型,你既可以将其作为参数传入 Cor ...
- objective-c中是如何实现线程同步的?
多线程在各种编程语言中都是难点,很多语言中实现起来很麻烦,objective-c虽然源于c,但其多线程编程却相当简单,可以与java相媲美.这篇文章主要从线程创建与启动.线程的同步与锁.线程的交互.线 ...
- iOS-开发日志-UITextView介绍
UITextView 属性 1. text: 设置textView中文本 _textView.text = @"Now is the time for all good develo ...
- POJ 3254 Corn Fields(DP + 状态压缩)
题目链接:http://poj.org/problem?id=3254 题目大意:Farmer John 放牧cow,有些草地上的草是不能吃的,用0表示,然后规定两头牛不能相邻放牧.问你有多少种放牧方 ...
- HDU_2014 青年歌手大奖赛_评委会打分
Problem Description 青年歌手大奖赛中,评委会给参赛选手打分.选手得分规则为去掉一个最高分和一个最低分,然后计算平均得分,请编程输出某选手的得分. Input 输入数据有多组,每 ...