众所周知,asp.net自带的GridView在自带分页方面设计得很2,因为它是假分页,即内存分页。而且它不智能支持强大的Iqueryable。
但这表明微软忽略了现实中的分页需求吗?答案应该不是,我想也不是。
那么,通过什么方式可以达到真分页的效果呢?使用Asp.Net自带的3种DataSource(objectdatasource, entitydatasource, linqdatasource)。 三种datasource各有所长。
但这样做还是有些麻烦呀……
朋友有一个项目,之前数据少,没有考虑过假分页带来的隐患,现在项目也做大了,数据也大了,问题也出来了,怎么办可以实现最少改动呢?废话不多说,直接上代码:
1 自定义一个PageGridView
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Reflection;
namespace DGVTest
{
public class PagingGridView : GridView
{
public PagingGridView()
{
}
private IQueryable querableData;
public override Object DataSource
{
get
{
return base.DataSource;
}
set
{
if (value is IQueryable)
{
querableData = (IQueryable)value;
ObjectDataSource ods = new ObjectDataSource();
ods.ID = "ods_" + this.ID;
ods.EnablePaging = this.AllowPaging;
// This must be the full name of the class
ods.TypeName = "DGVTest.IQueryableAdapter";
ods.SelectMethod = "GetData";
ods.SelectCountMethod = "GetCount";
ods.StartRowIndexParameterName = "startRowIndex";
ods.MaximumRowsParameterName = "pageSize";
ods.EnableViewState = false;
ods.ObjectCreating += (o,e)=> e.ObjectInstance =
new IQueryableAdapter(querableData);
base.DataSource = ods;
if (AllowPaging)
{
PageIndexChanging += (o, gpe) =>
{
PageIndex = gpe.NewPageIndex;
DataBind();
};
}
if (AllowSorting)
{
//---if want to implement sorting...
}
}
else
{
base.DataSource = value;
}
}
}
}
public class IQueryableAdapter
{
private IQueryable _data;
private int _totalCount;
public IQueryableAdapter(IQueryable data)
{
_data = data;
_totalCount = (int)GetExtMethod("Count", _data ).Invoke(null, new object[] { _data });
}
public object GetData()
{
return _data;
}
public int GetCount()
{
return _totalCount;
}
public object GetData(int startRowIndex, int pageSize)
{
var enumResult = GetExtMethod("Skip", _data).Invoke(null, new object[] { _data, startRowIndex });
return GetExtMethod("Take", _data ).Invoke(null, new object[] { enumResult, pageSize });
}
private MethodInfo GetExtMethod(string methodName,object obj )
{
var genType = obj.GetType().GetGenericArguments()[0];
return typeof(System.Linq.Queryable)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.First(m => m.Name == methodName)
.MakeGenericMethod(genType);
}
}
}
2 把这个新的GridView引入原项目
一般的做法是在页面上添加引用符:
<%@ Register Assembly="DGVTest" Namespace="DGVTest" TagPrefix="juyee" %>
然后把原GridView的前缀改了:
<juyee:PagingGridView ID="GridView1" runat="server" AllowPaging="True" AllowSorting="True"></juyee:PagingGridView>
但每个页面都加引用命令,还是很麻烦的。这可以通过在config解决:
<system.web>
<pages>
<controls>
<add tagPrefix="juyee" namespace="DGVTest"
assembly="DGVTest" />
</controls>
</pages>
</system.web>
有了这个,就不用每个页面加引用命令啦。至于替换gridview的声明嘛,可以用ctrl+F。
3 Code-Behind
现在可以直接把IQueryable类型的对象做为新View的数据源啦。值得一提的是,一定要orderby一下哟,不然执行IQueryable.Skip时会报错。
var ds= from t in new testdbEntities().People
orderby t.Name
select t;
GridView1.DataSource =ds;
GridView1.DataBind();
至此问题解决~赶快试试吧。