MVC学习笔记八:WebGrid控件的高级使用

WebGrid控件的高级使用

在笔记三中记录了WebGrid的简单使用,但实际工作中并不能满足开发要求,比如:考虑到性能,要求服务器端分页,而不是查出所有数据来进行简单的客户端页面分页;要在排序时,给列标题显示不同图像等等,都不是直接就能满足的,这里记录下对WebGrid进行的较高层次的使用。

一.服务器端分页处理

在演示服务端分页之前,先做一些简单的准备工作:

1.新建一个空的MVC 3项目,添加一个名为“GridController”的控制器;

2.在Model中增加一个“Movie”类;
代码如下:
   public class Movie
    {
        //主键
        public int Id { get; set; }

        //电影名称
        public string MovieName { get; set; }

        //票价
        public decimal TicketPrice { get; set; }

        //演播厅
        public string ShowAddress { get; set; }

        //上线日期
        public DateTime ShowTime { get; set; }

        //领衔主演
        public string Starring { get; set; }
    }
3.给控制器“GridController”的默认Index方法添加一个基于“Movie”的强类型视图,支架模板选择List;
为方便测试,修改Index方法为:
        public ActionResult Index()
        {
            List<Movie> movies = new List<Movie>()
            {
                new Movie(){ Id=1, MovieName="晚秋", Starring="汤唯", ShowAddress="苏州科文中心", ShowTime=DateTime.Parse("2014-4-10 15:00:00"), TicketPrice=25.5M},
                new Movie(){ Id=2, MovieName="神偷奶爸", Starring="XXX1", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-1 14:30:00"), TicketPrice=20.5M},
                new Movie(){ Id=3, MovieName="Yes Man", Starring="XXX2", ShowAddress="苏州印象城", ShowTime=DateTime.Parse("2014-5-2 14:25:00"), TicketPrice=21.5M},
                new Movie(){ Id=4, MovieName="里约大冒险", Starring="未知", ShowAddress="苏州石路", ShowTime=DateTime.Parse("2014-5-3 14:40:00"), TicketPrice=22.5M},
                new Movie(){ Id=5, MovieName="疯狂原始人", Starring="未知1", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-4 14:00:00"), TicketPrice=23.5M},
                new Movie(){ Id=6, MovieName="活着", Starring="葛优、巩俐", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-5 14:00:00"), TicketPrice=24.5M},
                new Movie(){ Id=7, MovieName="北京遇上西雅图", Starring="汤唯", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-6 14:00:00"), TicketPrice=26.5M},
                new Movie(){ Id=8, MovieName="人在囧途", Starring="徐峥", ShowAddress="XXX街影城", ShowTime=DateTime.Parse("2014-5-7 14:00:00"), TicketPrice=27.5M},
                new Movie(){ Id=9, MovieName="神探狄仁杰", Starring="未知", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-8 14:00:00"), TicketPrice=28.5M},
                new Movie(){ Id=10, MovieName="里约大冒险2", Starring="未知", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-9 14:00:00"), TicketPrice=29.5M},
            };

            return View(movies);
        }
4.为了使WebGrid界面美观一些,再添加一个CSS文件,代码如下:
body {
}
table {  
    border: solid 1px #e8eef4;  
    border-collapse: collapse;  
}  
  
table td {  
    padding: 5px;  
    border: solid 1px #e8eef4;  
    width:100px;  
    text-align:center ;
    background-color:orange;
}  
  
table th {  
    padding: 6px 5px;  
    text-align:center;  
    background-color:#CC99CC;  
    border: solid 1px #e8eef4;  
}  

.rowStyle  
{  
    background-color: #E8E8E8;  
    color: #000;  
}  
  
.gridhead {  
        background-color:yellow;  
    font-weight:bold;  
    text-align:center;  
} 
按照原先的简单做法,修改视图文件代码为:
@model IEnumerable<MvcWebGrid.Models.Movie>
@{
    ViewBag.Title = "我的WebGrid";
}

<h2>我的WebGrid示例</h2>

@{
    var grid = new WebGrid(

        source: Model,
        
        rowsPerPage: 4

        );
        
        
}

@grid.GetHtml(
tableStyle: "table",
headerStyle: "gridhead",
mode:WebGridPagerModes.All,
firstText:"首页",
lastText:"尾页",
previousText:"上一页",
nextText:"下一页",

columns:
grid.Columns(
    grid.Column("Id", "序号"),
    grid.Column("MovieName", "电影名"),
    grid.Column("Starring", "影院地址"),
    grid.Column("TicketPrice", "票价"),
    grid.Column("ShowAddress", "影院地址"),
    grid.Column("ShowTime", "上映日期")
)
)
运行网页,URL后加上:/grid
效果如下:

到此为止,是以前的做法,可以在页面进行分页,也可以排序,但是问题来了:

如果我后台数据量很大,假如有100万条,在每次重新运行该网页时,都会从数据库中查询出100W条数据,上面的做法只不过在客户端页面分页了一下,显示了4条,实际上我后台却作了查询100W条数据的工作量,而我们也许仅仅只要看某一页而已...

所以上面的分页做法肯定是不能满足性能要求的,这就要考虑使用服务端分页。

做法很简单,就是利用WebGrid页(如:第n页)和每页需要显示的行数(如:4行)来取数据:

举个简单的例子:如果我要看第1页,那么我只需要从数据库中查出前1~4条数据即可;要看第2页,只需要从数据库中查出从5~8条数据即可,依此类推, 要看第n页,只要从数据库中查出第(n-1)*4+1~4*n条数据即可。

接下来的问题就是考虑:如何让数据库去执行查询指定行的命令 ,其实很简单,不管用的是LINQ to Sql还是其它形式,无非就是 在前台查询指令,获得了WebGrid页和每页需要显示的行数的前提下,将指令转化成查询指定行的SQL

SqlServer查询指定行的SQL大家应该都知道的,如:
SELECT * FROM
(
  SELECT ROW_NUMBER() OVER( ORDER BY 排序的字段 ) AS 序号,表.* FROM 表
) tmp
WHERE tmp.序号 between xxx to xxxx
这里不用管它,只要知道最终是转化成这样的SQL即可。

现在的问题就是:我要在模型绑定时,知道WebGrid页---即用户点击了分页中的哪一页!这个十分简单,可以利用户点击下一页或上一页时,借助模型绑定,将webgrid页以参数形式传给action方法,即本例的Index方法,首先我得添加一个int型的参数:
        public ActionResult Index(int page=1)
        {
           //...
        }
其次,有了这个参数之后,后台就知道用户选了第几页,我后台就可以根据前面的算法,算出要查询第m~n行数据;
最后,后台查出数据之后,返回给页面数据,即Model,得借助webgrid的Bind方法动态绑定数据,由于分页还需要知道数据总行数来确定按钮个数,所以Model里必须要包含一个从后台查出数据的总行数,综上所述,我的Index视图就不能再是绑定原先的了,以下是做法:

1)在Model文件夹增加一个类,名称为“SelectMovies”:
    public class SelectMovies
    {
        //根据第n页查出的数据
        public List<Movie> selectMovies { get; set; }

        //数据总量
        public int totalCount { get; set; }

    }
2)修改Index方法为:
     public ActionResult Index(int page=1)
        {
            const int totalCount = 10;
            const int rowsPerPage = 4;

            List<Movie> movies = new List<Movie>()
            {
                new Movie(){ Id=1, MovieName="晚秋", Starring="汤唯", ShowAddress="苏州科文中心", ShowTime=DateTime.Parse("2014-4-10 15:00:00"), TicketPrice=25.5M},
                new Movie(){ Id=2, MovieName="神偷奶爸", Starring="XXX1", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-1 14:30:00"), TicketPrice=20.5M},
                new Movie(){ Id=3, MovieName="Yes Man", Starring="XXX2", ShowAddress="苏州印象城", ShowTime=DateTime.Parse("2014-5-2 14:25:00"), TicketPrice=21.5M},
                new Movie(){ Id=4, MovieName="里约大冒险", Starring="未知", ShowAddress="苏州石路", ShowTime=DateTime.Parse("2014-5-3 14:40:00"), TicketPrice=22.5M},
                new Movie(){ Id=5, MovieName="疯狂原始人", Starring="未知1", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-4 14:00:00"), TicketPrice=23.5M},
                new Movie(){ Id=6, MovieName="活着", Starring="葛优、巩俐", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-5 14:00:00"), TicketPrice=24.5M},
                new Movie(){ Id=7, MovieName="北京遇上西雅图", Starring="汤唯", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-6 14:00:00"), TicketPrice=26.5M},
                new Movie(){ Id=8, MovieName="人在囧途", Starring="徐峥", ShowAddress="XXX街影城", ShowTime=DateTime.Parse("2014-5-7 14:00:00"), TicketPrice=27.5M},
                new Movie(){ Id=9, MovieName="神探狄仁杰", Starring="未知", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-8 14:00:00"), TicketPrice=28.5M},
                new Movie(){ Id=10, MovieName="里约大冒险2", Starring="未知", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-9 14:00:00"), TicketPrice=29.5M},
            };

            var result = (from ms in movies select ms).Skip((page - 1) * rowsPerPage).Take(rowsPerPage);

            SelectMovies sm = new SelectMovies()
            {
                selectMovies = result.ToList(),
                totalCount=totalCount
            };

            return View(sm);
        }
3)修改Index视图:
@model MvcWebGrid.Models.SelectMovies

@{
    ViewBag.Title = "我的WebGrid";
}

<h2>我的WebGrid示例</h2>

@{
    var grid = new WebGrid(

        source: null,
        
        rowsPerPage: 4

        );

    grid.Bind(Model.selectMovies, rowCount: Model.totalCount, autoSortAndPage: false);
}

@grid.GetHtml(
tableStyle: "table",
headerStyle: "gridhead",
mode:WebGridPagerModes.All,
firstText:"首页",
lastText:"尾页",
previousText:"上一页",
nextText:"下一页",

columns:
grid.Columns(
    grid.Column("Id", "序号"),
    grid.Column("MovieName", "电影名"),
    grid.Column("Starring", "影院地址"),
    grid.Column("TicketPrice", "票价"),
    grid.Column("ShowAddress", "影院地址"),
    grid.Column("ShowTime", "上映日期")
)
)
编译运行,在Index方法中加个断点,可以看到每次供视图绑定的新模型中,仅仅只有4条数据,而不是起初的10条:

到目前为止,基本实现了服务端分页,但是又存在另一个问题,那就是排序被禁用了,如果还原那将不能实现服务端分页,接下来介绍如何在使用服务端分页的同时还能排序。

很简单,只要模型绑定时,给action方法提供两个参数:一个是排序字段,一个是排序方向(正/反排序)

这里只要修改Index方法的参数及代码实现,不过需要通过反射实现动态排序:
      public ActionResult Index(int page=1,string sort="Id",string sortDir="ASC")
        {
            const int totalCount = 10;
            const int rowsPerPage = 4;

            List<Movie> movies = new List<Movie>()
            {
                new Movie(){ Id=1, MovieName="晚秋", Starring="汤唯", ShowAddress="苏州科文中心", ShowTime=DateTime.Parse("2014-4-10 15:00:00"), TicketPrice=25.5M},
                new Movie(){ Id=2, MovieName="神偷奶爸", Starring="XXX1", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-1 14:30:00"), TicketPrice=20.5M},
                new Movie(){ Id=3, MovieName="Yes Man", Starring="XXX2", ShowAddress="苏州印象城", ShowTime=DateTime.Parse("2014-5-2 14:25:00"), TicketPrice=21.5M},
                new Movie(){ Id=4, MovieName="里约大冒险", Starring="未知", ShowAddress="苏州石路", ShowTime=DateTime.Parse("2014-5-3 14:40:00"), TicketPrice=22.5M},
                new Movie(){ Id=5, MovieName="疯狂原始人", Starring="未知1", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-4 14:00:00"), TicketPrice=23.5M},
                new Movie(){ Id=6, MovieName="活着", Starring="葛优、巩俐", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-5 14:00:00"), TicketPrice=24.5M},
                new Movie(){ Id=7, MovieName="北京遇上西雅图", Starring="汤唯", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-6 14:00:00"), TicketPrice=26.5M},
                new Movie(){ Id=8, MovieName="人在囧途", Starring="徐峥", ShowAddress="XXX街影城", ShowTime=DateTime.Parse("2014-5-7 14:00:00"), TicketPrice=27.5M},
                new Movie(){ Id=9, MovieName="神探狄仁杰", Starring="未知", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-8 14:00:00"), TicketPrice=28.5M},
                new Movie(){ Id=10, MovieName="里约大冒险2", Starring="未知", ShowAddress="观前街影城", ShowTime=DateTime.Parse("2014-5-9 14:00:00"), TicketPrice=29.5M},
            };

            IEnumerable<Movie> result;

            if (sortDir=="ASC")
            {
                 result = (from ms in movies orderby GetMovieProperty(ms, sort) ascending select ms).Skip((page - 1) * rowsPerPage).Take(rowsPerPage);
            }
            else
            {
                 result = (from ms in movies orderby GetMovieProperty(ms, sort) descending select ms).Skip((page - 1) * rowsPerPage).Take(rowsPerPage);
            }

            SelectMovies sm = new SelectMovies()
            {
                selectMovies = result.ToList(),
                totalCount=totalCount
            };

            return View(sm);
        }

        public object GetMovieProperty(object obj, string attrName)
        {
            var property = obj.GetType().GetProperty(attrName);
            object value = property.GetValue(obj, null);
            return value;
        }

以上,关于服务器分页及排序记录到此。



控件是基于Asp.Net平台的Web表格控件,用于Web网站的开发。 ★支持多种浏览器(IE6以上、FireFox2.0以上、谷歌浏览器等)。 ★使用控件开发的网站,网页上表格行的插入、追加、删除、修改、上下移动、拷贝、粘贴等操作,能够立即在浏览器客户端完成,操作按钮在上图表格的左下部。 ★提交后的数据为一个DataTable。用户可使用GetCommitData方法取得使用控件,很好地节约了网络资源,提升了网站的多用户对应能力。极大地提高了网页的反应速度,提升了网站浏览者的浏览体验。 ★本控件提供了丰富的自定义样式,供开发人员设定使用。表格(GridStyle)、奇偶行(ItemStyle、AlternatingItemStyle)、列(列的ItemStyle)、列内的控件(列的ControlStyle)、合计行(PageTotalStyle、AllTotalStyle)、控制行(包含各种行操作按钮和页操作按钮ToolBarStyle)都可以自由的进行样式设定。 ★提供多种类型的列供开发人员使用:(LabelColumn(图A-金额),TextBoxColumn(图A-数量、单价),DropDownListColumn(图A-类别、商品),RadioButtonListColumn(图A-发货区分),CheckBoxColumn(图A-包装有无),RowIndexColumn(图A-ID),HiddenColumn(隐藏列),TemplateColumn(图A-备注,模板,用于扩展)。 ★支持多行表头显示(图A),支持列合并(图A-发货区分)、行合并(图A-备注)。使用控件进行开发,开发人员能够自由设定各种显示效果。 ★支持开发人员自定义表头。 ★支持一个数据行,多行表格行表示。避免了列项目多的情况下,网页显示过宽的问题。(图A) ★支持金额、数字的自定义格式化功能。(图A-数量、单价,金额,金额美元) ★支持货币符号的自定义(如:$,¥)。(图A-金额,金额美元) ★支持列的公式自动计算功能。(图A-金额=数量×单价,金额美元=金额/汇率)列设定公式后,在网页上根据因子的变化自动计算结果。结合金额、数字的自定义格式化和货币符号的自定义功能,可开发专业性的财会、金融网站。 ★支持列的Ajax联动功能。特别定义了OnCallBack事件,开发人员能非常简单地实现Ajax联动,而页面不需要刷新。(图A-类别变化的时候,Ajax联动,更新了图A-商品列表) ★支持模板列(TemplateColumn),(图A-备注,模板)。并支持模板列的Ajax联动功能。模板列提供了扩展功能,使页面可以使用控件支持的列类型之外的控件类型。 ★支持自定义分页(图A定义每页大小为3行)。可由开发人员自行决定网页提交的模式,是小批量多批次,还是大批量少批次。本控件的灵活性提高了网站的灵活适应性。 ★本控件自动提供自带的分页控件,提供页的导航功能(图A右下部)。开发人员也可以禁止本控件提供的分页控件使用自己的分页控件或按钮调用本控件的分页功能。 ★表格行的上下移动功能,在分页的情况下,当需要跨页的情况下,自动提交数据,执行RowMoving事件,开发者可以在此事件中执行真正的数据行的上下移动,再绑定显示数据。 ★表格行的拷贝、粘贴功能,在分页的情况下,支持跨页执行,支持带Ajax联动列的直接拷贝。 ★支持操作的撤销、恢复功能,提升用户操作体验。 ★支持页合计和全部页合计。支持五种合计类型(Sum,Max,Min,Count,Average)。通过简单的开关设置,就可以完成合计功能。(图A-数量、金额、金额美元,设定了Sum合计;图A-单价,设定了Average合计)。 ★支持多种数据源。 ★所见即所得的设计时支持,方便软件开发者进行页面设计。 ★提供丰富、实用的JS接口,供开发人员使用。 ★本控件的开发中,力求功能的简洁、实用、耐用。提升开发人员的开发体验。 QQ:1030032915 MSN:IntelliGrid@hotmail.com
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值