[转]ASP.NET MVC 3 Razor + jqGrid 示例

本文转自:http://www.cnblogs.com/think8848/archive/2011/07/15/2107828.html

前些天写了一篇有关jqGrid的文章,因为是公司项目的原因一直没有提供源代码,今天又要用jqGrid,顺便做一个示例,以便有需要的人参考。源代码下载

为了使用方便起见,将jqGrid的一些选项放在了_Layout.cshtml中,这样就不用在每一个页面中重复输入了,见代码:

?
<!DOCTYPE html>
<html>
<head>
     <title>@ViewBag.Title</title>
     <link href= "@Url.Content(" ~/Content/themes/ base /site.css ")" rel= "Stylesheet" type= "text/css" />
     <link href= "@Url.Content(" ~/Content/themes/ base /jquery.ui.css ")" rel= "Stylesheet" type= "text/css" />
     <link href= "@Url.Content(" ~/Content/themes/ base /jquery.jqgrid.css ")" rel= "Stylesheet" type= "text/css" />
     <script src= "@Url.Content(" ~/Scripts/jquery.js ")" type= "text/javascript" ></script>
     <script src= "@Url.Content(" ~/Scripts/jquery.ui.js ")" type= "text/javascript" ></script>
     <script src= "@Url.Content(" ~/Scripts/i18n/grid.locale-cn.js ")" type= "text/javascript" ></script>
     <script src= "@Url.Content(" ~/Scripts/jquery.jqgrid.js ")" type= "text/javascript" ></script>
     <script type= "text/javascript" >
         var gridContainerId = '#gridview' , gridId = '#list' ;
         $(function () {
             $.extend($.jgrid.defaults, {
                 ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
                 datatype: 'json' ,
                 mtype: 'GET' ,
                 hidegrid: false ,
                 rownumbers: true ,
                 rowNum: 10,
                 rowList: [10, 15, 20],
                 sortorder: 'asc' ,
                 viewrecords: true ,
                 pager: $( '#pager' ),
                 height: 'auto' ,
                 editfunc: function (id, data) { return false ; },
                 delfunc: function (id, data) { return false ; },
                 cleverjqgridactions: 'clever_jqgrid_actions' ,
                 colActionsTitle: '操作'
             });
         });
         function cleverActions(cellvalue, options, rowObject) {
             return '<a href="javascript:void(0)" id="' + options.rowId + '" class="ui-corner-all clever-jqgrid-action clever-jqgrid-edit" style="float: left; margin-left: 5px; padding: 0px;" title="' + $.jgrid.nav.edittitle + '" onclick="actionClick(this,event)" onmouseover="actionMouseover(this,event)" onmouseout="actionMouseout(this,event)" ><span class="ui-icon ui-icon-pencil"></span></a>'
             + '<a href="javascript:void(0)" id="' + options.rowId + '" class="ui-corner-all clever-jqgrid-action clever-jqgrid-del" style="float: left; margin-left: 5px; padding: 0px;" title="' + $.jgrid.nav.deltitle + '" onclick="actionClick(this,event)" onmouseover="actionMouseover(this,event)" onmouseout="actionMouseout(this,event)" ><span class="ui-icon ui-icon-trash"></span></a>' ;
         }
         function actionMouseover(el, ev) {
             $(el).addClass( 'ui-state-hover' );
             if ($.browser.msie) {
                 ev.cancelBubble = true ;
             } else {
                 ev.stopPropagation();
             }
         }
         function actionMouseout(el, ev) {
             $(el).removeClass( 'ui-state-hover' );
             if ($.browser.msie) {
                 ev.cancelBubble = true ;
             } else {
                 ev.stopPropagation();
             }
         }
         function actionClick(el, ev) {
             var id = $(el).attr( 'id' );
             var data = $(gridId).jqGrid( 'getRowData' , id);
             if (data.clever_jqgrid_actions) {
                 delete data.clever_jqgrid_actions;
             }
             if ($(el).hasClass( 'clever-jqgrid-edit' )) {
                 $(gridId).getGridParam( 'editfunc' )(id, data);
             } else if ($(el).hasClass( 'clever-jqgrid-del' )) {
                 if (confirm($.jgrid.del.msg)) {
                     $(gridId).getGridParam( 'delfunc' )(id, data);
                 }
             }
             if ($.browser.msie) {
                 ev.cancelBubble = true ;
             } else {
                 ev.stopPropagation();
             }
         }
     </script>
     @RenderSection( "header" , false )
     <script type= "text/javascript" >
         $(function () {
             $(window).bind( 'resize' , function () {
                 var width = $(gridContainerId).width();
                 if (width == null || width < 1) {
                     width = $(gridContainerId).attr( 'offsetWidth' );
                 }
                 width = width - 2;
                 if (width > 0 && Math.abs(width - $(gridId).width()) > 5) {
                     $(gridId).setGridWidth(width);
                 }
             }).trigger( 'resize' );
         });   
     </script>
</head>
<body>
     @RenderBody()
</body>
</html>

为了使jqGrid能随着浏览器的缩放而自适应宽度,因此我在视图页面执行完javascript后又为jqGrid指定了resize事件。

在这里值的一提的是,要为jqGrid指定默认选项,需要使用$.jgrid.defaults,方法嘛当然是继承了,这里我把部分默认选项的说明给出来:

//指定请求数据时的ContentType,我使用了json

ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },

//返回数据格式为json

datatype: 'json',

//Http方法为GET

mtype: 'GET',

//隐藏Grid的头

hidegrid: false,

//是否显示行号

rownumbers: true,

//默认显示数据行的个数

rowNum: 10,

//允许显示数据行个数的选项

rowList: [10, 15, 20],

//默认排序策略(升序)

sortorder: 'asc',

//是否显示表脚,即翻页所在的那行

viewrecords: true,

//页脚的容器

pager: $('#pager'),

//Grid高度自动调整

hieght: 'auto',

//这是我自定义的一个功能,后面会提到

editfunc: function (id, data) { return false; },

//自定义功能,同上

delfunc: function (id, data) { return false; },

 

//自定义功能,同上

cleverjqgridactions: 'clever_jqgrid_actions',

//自定义功能,同上

colActionsTitle: '操作'

一般情况下,在管理系统中,需要尽可能的减少用户的操作步骤,因此,把"编辑","删除"按钮直接放在数据行中,这样用户点一下就可以了,而不需要先选中一行,然后再去点击编辑/删除按钮,因此,使用自定义Formatter的方式,使每行增加一个"编辑","删除"按钮,方法如下:

在colModel中添加一个列:

?
{ name: $.jgrid.defaults.cleverjqgridactions, width: 80, fixed: true , sortable: false , resize: false , formatter: cleverActions }

 

?
上文中$.jgrid.defaults.cleverjqgridactions就是这个用途,为这个列提供一个不大可能重复的固定列定,以标示这个列,重点是formatter,为这个选项提供一个方法便是,这个方法的签名如下:
?
function (cellvalue, options, rowObject){
}
?
cellValue不用理会,因为它本来是指json为这个列提从的值,因为我们这个项不是json提供的,所以它肯定为undefined;
?
options里提供了这个列的定义(colModel中列的定义选项),该字段所在行的主键值(当然,得是你指定了某行为主键),以及jqGrid的id;
?
rowObject是一个数组,为截止目前,所在行的json数据,为啥是截止目前呢?因为当你这一列定义成功后,本列也成为行数据的一员了,在实际应用中,你肯定不希望这列的数据(其实就是你定义的按钮的HTML字符串)作为正式数据传入到业务逻辑里吧,所以使用 delete 方法要删除行数据中的这个字段值,那如何获取这个字段的名称呢?当..当..当,还记得$.jgrid.defaults.cleverjqgridactions吗?当然是使用它了(貌似是一个锉方法哦?)。
?
ok,知道了这些,我们来定义一个自定义的formatter:
?
function cleverActions(cellvalue, options, rowObject) {
     return '<a href="javascript:void(0)" id="' + options.rowId + '" class="ui-corner-all clever-jqgrid-action clever-jqgrid-edit" style="float: left; margin-left: 5px; padding: 0px;" title="' + $.jgrid.nav.edittitle + '" onclick="actionClick(this,event)" onmouseover="actionMouseover(this,event)" onmouseout="actionMouseout(this,event)" ><span class="ui-icon ui-icon-pencil"></span></a>'
     + '<a href="javascript:void(0)" id="' + options.rowId + '" class="ui-corner-all clever-jqgrid-action clever-jqgrid-del" style="float: left; margin-left: 5px; padding: 0px;" title="' + $.jgrid.nav.deltitle + '" onclick="actionClick(this,event)" onmouseover="actionMouseover(this,event)" onmouseout="actionMouseout(this,event)" ><span class="ui-icon ui-icon-trash"></span></a>' ;
}
?
使用$.jgrid.nav.edittitle和$.grid.nav.deltitle能获取到本地化的 "编辑" , "删除" 字符串,这样当用户把鼠标移动上按钮上时,就可以知道这两个按钮是什么用途了,所以将它哥俩的值指定给了a的title。
?
另外,我希望在我点击了 "编辑" 或是 "删除" 按钮时,就不要再触发行选中事件了,因此,我中止了事件冒泡,同样,我也中止了按钮的mouseover和mouseout事件冒泡:
?
function actionMouseover(el, ev) {
     $(el).addClass( 'ui-state-hover' );
     if ($.browser.msie) {
         ev.cancelBubble = true ;
     } else {
         ev.stopPropagation();
     }
}
function actionMouseout(el, ev) {
     $(el).removeClass( 'ui-state-hover' );
     if ($.browser.msie) {
         ev.cancelBubble = true ;
     } else {
         ev.stopPropagation();
     }
}
function actionClick(el, ev) {
     var id = $(el).attr( 'id' );
     var data = $(gridId).jqGrid( 'getRowData' , id);
     if (data.clever_jqgrid_actions) {
         delete data.clever_jqgrid_actions;
     }
     if ($(el).hasClass( 'clever-jqgrid-edit' )) {
         $(gridId).getGridParam( 'editfunc' )(id, data);
     } else if ($(el).hasClass( 'clever-jqgrid-del' )) {
         if (confirm($.jgrid.del.msg)) {
             $(gridId).getGridParam( 'delfunc' )(id, data);
         }
     }
     if ($.browser.msie) {
         ev.cancelBubble = true ;
     } else {
         ev.stopPropagation();
     }
}
?
代码看到这里,我直是讨厌IE,就是整得和别人不一样。好好的就使用stopPropagation嘛,非得整啥cancelBubble呢?
?
var id = $(el).attr( 'id' );
var data = $(gridId).jqGrid( 'getRowData' , id);
?
鉴于在点击按钮后再获取行的主键值比较困难,我在生成铵钮时就将行主键值存在a标签的id中了,因此此时取出来,再使用getRowData方法获取该主键所在的行的数据对象,getRowData方法,据官方文档中说,性能不高,使用需谨慎,不要使用在 for 或是 while 中。
?
if (data.clever_jqgrid_actions) {
     delete data.clever_jqgrid_actions;
}
?
如果行数据包含了按钮HTML文本,则删除数据的这个属性
?
$(gridId).getGridParam( 'editfunc' )(id, data);
?
使用getGridParam方法调用当点击了编辑按钮时的回调方法。
?
ok,至此,在_Layout.cshtml中的故事就讲完了,接下来我们来看看在实际使用的页面中是如何编码的:
?
@{
     ViewBag.Title = "Index";
}
@section header{
     < script type="text/javascript">
         $(function () {
             $('#list').jqGrid({
                 url: '@Url.Action("Index", "User")',
                 colNames: ['Primary Key', 'User Name', 'Email', $.jgrid.defaults.colActionsTitle],
                 colModel: [
                 { name: 'ID', index: 'ID', width: 1, hidden: true, key: true },
                 { name: 'Name', index: 'Name', width: 100, align: 'left' },
                 { name: 'Mail', index: 'Mail', width: 100, align: 'left' },
                 { name: $.jgrid.defaults.cleverjqgridactions, width: 80, fixed: true, sortable: false, resize: false, formatter: cleverActions }
                 ],
                 sortname: 'Name',
                 multiselect: true,
                 editfunc: function (id, data) {
                     alert(id);
                 },
                 delfunc: function (id, data) {
                     alert(id);
                 }
             });
         });
     </ script >
}
< div id="gridview">
     < table id="list">
     </ table >
     < div id="pager">
     </ div >
</ div >
?
有了_Layout.cshtml中的代码,这个页面上的代码就少多了,至少看起来不那么吓人了,照例来讲讲参数吧:
?
//地球人都知道,这是请求数据的url
?
url: '@Url.Action("Index", "User")' ,
?
//显示用的表头数据,$.jgrid.defaults.colActionsTitle本来的用途是显示"操作"两个字,但是不见得我在每个视图的资源文件中都定义吧,所以还是定义在_Layout.cshtml中,这样使用js的方式调用好可
?
colNames: ['Primary Key', 'User Name', 'Email', $.jgrid.defaults.colActionsTitle],
//定义数据列
?
colModel: [{ 
?
//列名
?
name: 'ID',
?
//排序时的键
?
index: 'ID',
?
//宽度,应该是px单位
?
width: 1, 
?
//隐藏
?
hidden: true,
?
//标示主键列
?
key: true },
                 { name: 'Name', index: 'Name', width: 100, align: 'left' },
                 { name: 'Mail', index: 'Mail', width: 100, align: 'left' },
                 { name: $.jgrid.defaults.cleverjqgridactions, width: 80, fixed: true, sortable: false, resize: false, formatter: cleverActions }
                 ],
//默认使用Name列排序
?
sortname: 'Name',
//是否允许多选,这个选项为true,则前面会加上一个全是checkbox的列,作用不用我多说了吧
?
multiselect: true,
//自定义formatter中编辑按钮的回调方法,id是本行的主键值,data是本行的所有数据
?
editfunc: function (id, data) {
                     alert(ids);
                 },
?
//自定义formatter中删除按钮的回调方法
delfunc: function (id, data) {
                     alert(ids);
                 }
?
有了这些差不多jqGrid就能很好的工作起来了,但是服务端的数据处理起来也够麻烦的,think8848一向作人厚道,因此专门写了两个助手类,专为jqGrid提供格式化的数据:
?
/// <summary>
/// 分页排序助手类
/// </summary>
public static class DataPagingHelper
{
     public static IQueryable<T> GetQueryable<T>( this IList<T> list, string sidx, string sord, int page, int rows)
     {
         return GetQueryable<T>(list.AsQueryable<T>(), sidx, sord, page, rows);
     }
 
     public static IQueryable<T> GetQueryable<T>( this IQueryable<T> queriable, string sidx, string sord, int page, int rows)
     {
         var data = ApplyOrder<T>(queriable, sidx, sord.ToLower() == "asc" ? true : false );
 
         return data.Skip<T>((page - 1) * rows).Take<T>(rows);
     }
 
     private static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> queriable, string property, bool isASC)
     {
         PropertyInfo pi = typeof (T).GetProperty(property);
         ParameterExpression arg = Expression.Parameter( typeof (T), "x" );
         Expression expr = Expression.Property(arg, pi);
 
         Type delegateType = typeof (Func<,>).MakeGenericType( typeof (T), pi.PropertyType);
         LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
 
         string methodName = isASC ? "OrderBy" : "OrderByDescending" ;
 
         object result = typeof (Queryable).GetMethods().Single(
                 method => method.Name == methodName
                         && method.IsGenericMethodDefinition
                         && method.GetGenericArguments().Length == 2
                         && method.GetParameters().Length == 2)
                 .MakeGenericMethod( typeof (T), pi.PropertyType)
                 .Invoke( null , new object [] { queriable, lambda });
 
         return (IOrderedQueryable<T>)result;
     }
}
 
/// <summary>
/// jqGrid数据处理助手类
/// </summary>
public static class JqGridHelper
{
     public static JsonResult GetJson<T>( this IList<T> datas, string sidx, string sord, int page, int rows, JsonRequestBehavior behavior, params string [] fields)
     {
         return GetJson<T>(datas.AsQueryable<T>(), sidx, sord, page, rows, behavior, fields);
     }
 
     public static JsonResult GetJson<T>( this IQueryable<T> queriable, string sidx, string sord, int page, int rows, JsonRequestBehavior behavior, params string [] fields)
     {
         var data = queriable.GetQueryable<T>(sidx, sord, page, rows);
 
         var json = new JsonResult();
         json.JsonRequestBehavior = behavior;
 
         if (rows != 0)
         {
             var totalpages = ( decimal )queriable.Count<T>() / ( decimal )rows;
             totalpages = (totalpages == ( int )totalpages) ? totalpages : ( int )totalpages + 1;
 
             var rowsData = GetJsonData<T>(data, fields);
 
             json.Data = new
             {
                 page,
                 records = rows,
                 total = ( int )totalpages,
                 rows = rowsData
             };
         }
 
         return json;
     }
 
     private static object [] GetJsonData<T>(IQueryable<T> queriable, params string [] fields)
     {
         var properties = typeof (T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
 
         T[] datas = queriable.ToArray<T>();
 
         object [] result = new object [datas.Length];
 
         if (fields.Length == 0)
         {
             fields = Array.ConvertAll<PropertyInfo, string >(properties.Where<PropertyInfo>
                 (x => x.GetCustomAttributes( typeof (InternalAttribute), false ).Length == 0)
                 .ToArray<PropertyInfo>()
                 , delegate (PropertyInfo p)
                 {
                     return p.Name;
                 });
         }
 
         for ( int i = 0; i < datas.Length; i++)
         {
             object [] values = new object [fields.Length];
             for ( int j = 0; j < fields.Length; j++)
             {
                 var pi = properties.First<PropertyInfo>(x => x.Name == fields[j]);
                 var value = pi.GetValue(datas[i], null );
                 values[j] = value != null ? value.ToString() : "" ;
             }
 
             result[i] = new { id = i, cell = values };
         }
 
         return result;
     }
}
 
/// <summary>
/// 本人项目中使用的,不用深究
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class InternalAttribute : Attribute { }
?
有了这两个助手类,我们再来看提供数据的服务是啥样的:
?
public class UserController : Controller
{
     //
     // GET: /User/
 
     public ActionResult Index( string sidx, string sord, int page, int rows)
     {
         var users = new List<User>();
         users.Add( new User() { ID = Guid.NewGuid(), Name = "think8848" , Mail = "think8848@csdn.net" , Password = "abcdefg" });
         users.Add( new User() { ID = Guid.NewGuid(), Name = "a" , Mail = "a@csdn.net" , Password = "abcdefg" });
         users.Add( new User() { ID = Guid.NewGuid(), Name = "b" , Mail = "b@csdn.net" , Password = "abcdefg" });
         //...
         users.Add( new User() { ID = Guid.NewGuid(), Name = "y" , Mail = "y@csdn.net" , Password = "abcdefg" });
         users.Add( new User() { ID = Guid.NewGuid(), Name = "z" , Mail = "z@csdn.net" , Password = "abcdefg" });
 
         return users.GetJson<User>(sidx, sord, page, rows, JsonRequestBehavior.AllowGet, new string [] { "ID" , "Name" , "Mail" });
     }
}
?
User实体定义:
?
public class User
{
     public Guid ID { get ; set ; }
     public string Name { get ; set ; }
     public string Password { get ; set ; }
     public string Mail { get ; set ; }
}
?
必须得完结了,我的脚被蚊子要抬走了...
?
效果图:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值