一、概述:
Datagrid在web应用程式中经常用到,但是Datagrid控件本身提拱的排序,分页功能对于有着大量记录的表来说,按它的做法是不现实的,如一个表有20万记录,按Datagrid本身的排序和分页的原理,必须把所有的记录全部取回,再进行分页,这对服务器的内存及响应的速度是一个挑战。本论文提供了这样一个解决方案,就是只从数据库中取回你所需要的且符合条件的记录,这样响应时间会大大的提高,内存开销也可减少。
二、实现的功能:
1、在页面上按指定的格式显示从数据库中取回的数据(用Datagrid控件显示)。
2、对记录进行分页(必须在数据库内进行分页,即传入第几页,每页记录数,就传回己分好页的记录)
3、点击Datagrid标头后以实现重新排序显示,且有点击第一次按降序,点击第二次按升序(不是对已显示的记录进行排序,而是重新到数据库中取出符合条件的并按指定顺序排序的指定页记录)
4、可以通过点击Datagrid的CheckBox框以实现全选和全不选功能,且支持群体操作(如删除,转入等)
三、制约条件
1、数据库表必须有一个关键字段或有一个唯一字段。
四、制作过程(范例):
1、数据库结构:
本范例是用SQL Server自带的数据库Northwind为例,表为Customers
代码编写过程:
1、首先用户新加一个窗体。
2、在窗体上放置一个五个LinkButton控件,并设置ID为:lkbDel,LinkButtonPreview,LinkButtonNext,LinkButtonLast,LinkButtonFirst,设置各控件的Text属性为:“删除”,“首页”,“上一页”,“下一页”,及“尾页”,放置位置如上图;同时在窗体上放一个Datagrid控件,控件的名称为:dgList
3、把dgList控件的AutoSortint属性设为true,AutoGenarateColumes属性设为false,DataKeyField属性设为CustomerID,Width属性设为100%,设置dgList控件的各列如下:
<Columns>
<asp:TemplateColumn>
<HeaderStyle Width="10px"></HeaderStyle>
<HeaderTemplate>
<INPUT id="chkselectall" type="checkbox" onclick="checkallorno(this)"></asp:CheckBox>
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox id="chkselect" runat="server"></asp:CheckBox>
</ItemTemplate>
</asp:TemplateColumn>
<asp:BoundColumn DataField="CustomerID" SortExpression="CustomerID" HeaderText="ID"></asp:BoundColumn>
<asp:BoundColumn DataField="CompanyName" SortExpression="CompanyName" HeaderText="客户名称"></asp:BoundColumn>
<asp:BoundColumn DataField="ContactName" SortExpression="ContactName" HeaderText="联系名称"></asp:BoundColumn>
<asp:BoundColumn DataField="ContactTitle" SortExpression="ContactTitle" HeaderText="职位"></asp:BoundColumn>
<asp:BoundColumn DataField="Phone" SortExpression="Phone" HeaderText="电话"></asp:BoundColumn>
<asp:BoundColumn DataField="Fax" SortExpression="Fax" HeaderText="传真"></asp:BoundColumn>
</Columns>
其中第一列是必须的,其他列可根据情况自己增加或删除。
其中上段代码中点击标头的CheckBox后实现所有的显示项的全选或全不选的功能是由一个javascript的checkallorno(this)函来实现的,具体函数体如下:
<script>
function checkallorno(o)
{
var a=o;
while(true)
{
var a=a.parentElement;
if(a==null)
{
break;
}
if(a=="undefined")
{
a=null;
break;
}
if(a.tagName=="TABLE")
{
break;
}
}
if(a!=null)
{
for(i=0;i<a.rows.length;i++)
{
for(j=0;j<a.rows[i].cells[0].children.length;j++)
{
var var1=a.rows[i].cells[0].children[j];
if(var1.tagName=="INPUT" )
{
if(var1.type=="checkbox")
{
var1.checked=o.checked;
}
}
}
}
}
}
</script>
同时设置dgList的SortCommand为dgList_SortCommand()具体实现看原码。
4、设置lkbDel的的Click事件为如下:lkbDel_Click(object sender, System.EventArgs e),当然该事件名你可以随便取名,同时设置LinkButtonPreview,LinkButtonNext,LinkButtonLast,LinkButtonFirst的Click事件为同一个函数(怎样设置事件请看MSDN)。函数名为:dgList_SortCommand(object source, System.Web.UI.WebControls.DataGridSortCommandEventArgs e);各事件的具体实现请看源代码,在类里放两个变量如下:
//这是每次每页显示的记录数.
private int RecordPerPage=6;
//这个变量为数据库联接
protected string m_cnnstr="data source=Robert\Robert;initial catalog=Northwind;User id=sa;pwd=";
5、在page_Load事件中加入以下代码:
private void Page_Load(object sender, System.EventArgs e)
{
if(!this.IsPostBack)
{
/*this.ViewState["TotalRecord"]
* 用于记录总共有多少条记录
* */
this.ViewState["TotalRecord"]=GetTatolRecordNumber();
/*this.ViewState["TotalRecord"]
* 用于记录当前显示第几条记录
* */
this.ViewState["CurrentPg"]=1;
/*this.ViewState["Sort"]
*用于存放当前的排序字符串
* */
this.ViewState["Sort"]="";
//对导行栏的状态进行初始化.
setGuide(null);
//第一次显示记录.
ShowData();
}
}
其中GetTatolRecordNumber();是取回总记录数,setGuide(null);是设置分页相关按钮的状态, ShowData();是用来设置dgList控件数据源,这两人函数的具体实现请看源代码。
aspx原码:
<%@ Page language="c#" Codebehind="Pagination.aspx.cs" AutoEventWireup="false" Inherits="SortAndPagination.Pagination" %>
<%@ Register TagPrefix="iewc" Namespace="Microsoft.Web.UI.WebControls" Assembly="Microsoft.Web.UI.WebControls, Version=1.0.2.226, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>Pagination</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
<script>
function checkallorno(o)
{
var a=o;
while(true)
{
var a=a.parentElement;
if(a==null)
{
break;
}
if(a=="undefined")
{
a=null;
break;
}
if(a.tagName=="TABLE")
{
break;
}
}
if(a!=null)
{
for(i=0;i<a.rows.length;i++)
{
for(j=0;j<a.rows[i].cells[0].children.length;j++)
{
var var1=a.rows[i].cells[0].children[j];
if(var1.tagName=="INPUT" )
{
if(var1.type=="checkbox")
{
var1.checked=o.checked;
}
}
}
}
}
}
</script>
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<FONT face="宋体">
<TABLE cellSpacing="1" cellPadding="1" width="100%" border="1">
<tr>
<td align="center" colSpan="2"><STRONG><FONT size="4">关于排序,分页,多条记录选择及删除的范例</FONT></STRONG>
</td>
</tr>
<TR>
<TD align="right" colSpan="2"><SPAN onclick="return window.confirm('你真要删除所选项?')"><asp:linkbutton id="lkbDel" runat="server">删除</asp:linkbutton></SPAN></TD>
</TR>
<TR>
<TD colSpan="2"><asp:datagrid id="dgList" runat="server" DataKeyField="CustomerID" Width="100%" AllowSorting="True"
AutoGenerateColumns="False" PageSize="20">
<Columns>
<asp:TemplateColumn>
<HeaderStyle Width="10px"></HeaderStyle>
<HeaderTemplate>
<INPUT id="chkselectall" type="checkbox" onclick="checkallorno(this)"></asp:CheckBox>
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox id="chkselect" runat="server"></asp:CheckBox>
</ItemTemplate>
</asp:TemplateColumn>
<asp:BoundColumn DataField="CustomerID" SortExpression="CustomerID" HeaderText="ID"></asp:BoundColumn>
<asp:BoundColumn DataField="CompanyName" SortExpression="CompanyName" HeaderText="客户名称"></asp:BoundColumn>
<asp:BoundColumn DataField="ContactName" SortExpression="ContactName" HeaderText="联系名称"></asp:BoundColumn>
<asp:BoundColumn DataField="ContactTitle" SortExpression="ContactTitle" HeaderText="职位"></asp:BoundColumn>
<asp:BoundColumn DataField="Phone" SortExpression="Phone" HeaderText="电话"></asp:BoundColumn>
<asp:BoundColumn DataField="Fax" SortExpression="Fax" HeaderText="传真"></asp:BoundColumn>
</Columns>
</asp:datagrid></TD>
</TR>
<tr>
<TD align="right" colSpan="2">
<TABLE id="Table1" cellSpacing="1" cellPadding="1" border="0">
<TR>
<TD noWrap><asp:linkbutton id="LinkButtonFirst" runat="server">首页</asp:linkbutton></TD>
<TD>|</TD>
<TD noWrap><asp:linkbutton id="LinkButtonPreview" runat="server">上一页</asp:linkbutton></TD>
<TD>|</TD>
<TD noWrap><asp:linkbutton id="LinkButtonNext" runat="server">下一页</asp:linkbutton></TD>
<TD>|</TD>
<TD noWrap><asp:linkbutton id="LinkButtonLast" runat="server">尾页</asp:linkbutton></TD>
</TR>
</TABLE>
</TD>
</tr>
</TABLE>
</FONT>
</form>
</body>
</HTML>
aspx.cs原码:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace SortAndPagination
{
/// <summary>
/// 关于排序,分页,多条记录选择及删除的范例
/// </summary>
public class Pagination : System.Web.UI.Page
{
protected System.Web.UI.WebControls.DataGrid dgList;
protected System.Web.UI.WebControls.LinkButton lkbDel;
protected System.Web.UI.WebControls.LinkButton LinkButtonPreview;
protected System.Web.UI.WebControls.LinkButton LinkButtonNext;
protected System.Web.UI.WebControls.LinkButton LinkButtonLast;
protected System.Web.UI.WebControls.LinkButton LinkButtonFirst;
//这是每次每页显示的记录数.
private int RecordPerPage=6;
//这个变量为数据库联接
protected string m_cnnstr="data source=devserver-1;initial catalog=Northwind;User id=sa;pwd=";
private void Page_Load(object sender, System.EventArgs e)
{
if(!this.IsPostBack)
{
/*this.ViewState["TotalRecord"]
* 用于记录总共有多少条记录
* */
this.ViewState["TotalRecord"]=GetTatolRecordNumber();
/*this.ViewState["TotalRecord"]
* 用于记录当前显示第几条记录
* */
this.ViewState["CurrentPg"]=1;
/*this.ViewState["Sort"]
*用于存放当前的排序字符串
* */
this.ViewState["Sort"]="";
//对导行栏的状态进行初始化.
setGuide(null);
//第一次显示记录.
ShowData();
}
}
#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.lkbDel.Click += new System.EventHandler(this.lkbDel_Click);
this.dgList.SortCommand += new System.Web.UI.WebControls.DataGridSortCommandEventHandler(this.dgList_SortCommand);
this.LinkButtonFirst.Click += new System.EventHandler(this.Guid_Click);
this.LinkButtonPreview.Click += new System.EventHandler(this.Guid_Click);
this.LinkButtonNext.Click += new System.EventHandler(this.Guid_Click);
this.LinkButtonLast.Click += new System.EventHandler(this.Guid_Click);
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
private void ShowData()
{
string order=this.ViewState["Sort"].ToString();
//构告SQL的排序字符串
if(order!="")
{
order=" Order By "+order+" ";
}
int StartNum=(int)this.ViewState["CurrentPg"]*RecordPerPage;
int intTemNum=StartNum-RecordPerPage;
string l_SQL="select * from (select top "+StartNum.ToString()
+" * from Customers "+order+") a "
+" where a.CustomerID not in (Select top "+intTemNum.ToString()
+" CustomerID From Customers "+order+")";
System.Data.SqlClient.SqlConnection
l_cnn=new System.Data.SqlClient.SqlConnection(this.m_cnnstr);
System.Data.SqlClient.SqlDataAdapter
l_apd=new System.Data.SqlClient.SqlDataAdapter(l_SQL,l_cnn);
System.Data.DataTable l_dt=new DataTable("tem");
l_apd.Fill(l_dt);
this.dgList.DataSource=l_dt;
this.dgList.DataBind();
}
/// <summary>
/// 这是用来获取当前总共在数据库中有多少条记录
/// </summary>
/// <returns>返回记录数</returns>
private int GetTatolRecordNumber()
{
System.Data.SqlClient.SqlConnection
l_cnn=new System.Data.SqlClient.SqlConnection(this.m_cnnstr);
l_cnn.Open();
System.Data.SqlClient.SqlCommand
l_scd=l_cnn.CreateCommand();
l_scd.CommandText="Select Count(*) From Customers";
System.Data.SqlClient.SqlDataReader
l_sdr=l_scd.ExecuteReader();
l_sdr.Read();
//取出总记录数
int l_count=l_sdr.GetInt32(0);
l_cnn.Close();
return l_count;
}
private void dgList_SortCommand(object source, System.Web.UI.WebControls.DataGridSortCommandEventArgs e)
{
string l_CurrentSort=e.SortExpression;
//记录排序字符串
this.ViewState["Sort"]= l_CurrentSort;
foreach(System.Web.UI.WebControls.DataGridColumn l_dgc in this.dgList.Columns)
{
/*判断是哪一列要进行排序
以便第二次点击时是别外一个顺序
**/
if(l_dgc.SortExpression==l_CurrentSort)
{
l_CurrentSort=l_CurrentSort.Trim();
//这里只是简单的把字段与排序关键字分开,你可以用正则表达式来做会更好
string [] l_arr_str=l_CurrentSort.Split(new char[]{' '});
if(l_arr_str.Length==1)//如果没有后面的排序关键字,则认为它是升序,下次则要改为降序
{
l_dgc.SortExpression=l_arr_str[0]+" desc";
}
else
{
if(l_arr_str[l_arr_str.Length-1].ToLower()=="asc")//如果原来为升序,则改为降序
{
l_dgc.SortExpression=l_arr_str[0]+" desc";
}
else//如果原来为降序,则改为升序
{
l_dgc.SortExpression=l_arr_str[0]+" asc";
}
}
break;//完成排序头更改
}
}
//重新从数据库中取记录并进行排序显示.
try
{
ShowData();
}
catch(Exception ex)
{
this.Response.Write("<font color=red>"+ex.Message+"</font>");
}
}
private void Guid_Click(object sender, System.EventArgs e)
{
try
{
setGuide(sender);
ShowData();
}
catch(Exception ex)
{
this.Response.Write("<font color=red>"+ex.Message+"</font>");
}
}
/// <summary>
/// 这是用来显示导行栏中每个元素的状态
/// </summary>
/// <param name="sender">表示是按的那一个导行栏元素的按钮,如果不是由导行栏触发,则传null值</param>
private void setGuide(object sender)
{
int m_iTotalPage = Convert.ToInt32(System.Math.Ceiling(Convert.ToDouble((int)this.ViewState["TotalRecord"])/Convert.ToDouble(this.RecordPerPage)));
if(m_iTotalPage<(int)this.ViewState["CurrentPg"])
this.ViewState["CurrentPg"]=1;
if(sender==this.LinkButtonFirst)
{
this.ViewState["CurrentPg"]=1;
}
if(sender==this.LinkButtonNext)
{
this.ViewState["CurrentPg"]=(int)this.ViewState["CurrentPg"]+1;
}
if(sender==this.LinkButtonPreview)
{
this.ViewState["CurrentPg"]=(int)this.ViewState["CurrentPg"]-1;
}
if(sender==this.LinkButtonLast)
{
this.ViewState["CurrentPg"]=m_iTotalPage;
}
this.LinkButtonFirst.Enabled=!((int)this.ViewState["CurrentPg"]==1);
this.LinkButtonPreview.Enabled=!((int)this.ViewState["CurrentPg"]==1);
this.LinkButtonLast.Enabled=!((int)this.ViewState["CurrentPg"]==m_iTotalPage);
this.LinkButtonNext.Enabled=!((int)this.ViewState["CurrentPg"]==m_iTotalPage);
}
private void lkbDel_Click(object sender, System.EventArgs e)
{
/*
* 下面是用来确定有哪些记录被选种要删除的.
* 由于CustomerID是Char类型的,
* 所以用如下形式来收集该字符串以便在构建删除语句的时候用
* "'DDFG','CCFE','FDDD'"
* */
string l_str_id="";
foreach(System.Web.UI.WebControls.DataGridItem l_dgl in this.dgList.Items)
{
//chkselect是每个记录项的ID,记住,这是服务器端的ID,不是客户端的ID.
System.Web.UI.Control l_ct=l_dgl.Cells[0].FindControl("chkselect");
if(l_ct!=null)
{
//下面语句是判断是否记录项的checkbox框初选种
if(((System.Web.UI.WebControls.CheckBox)l_ct).Checked)
{
if(l_str_id=="")
l_str_id="'"+this.dgList.DataKeys[l_dgl.ItemIndex].ToString()+"'";
else
l_str_id+=",'"+this.dgList.DataKeys[l_dgl.ItemIndex].ToString()+"'";
}
}
}
/*
* 下面语句是用来删除所选种的ID,"CustomerID"是CustomerID的关键字.
* */
try
{
if(l_str_id!="")
{
System.Data.SqlClient.SqlConnection
l_cnn=new System.Data.SqlClient.SqlConnection(this.m_cnnstr);
l_cnn.Open();
System.Data.SqlClient.SqlCommand
l_scd=l_cnn.CreateCommand();
l_scd.CommandText="Delete From Customers where CustomerID in ("
+l_str_id+")";
l_scd.ExecuteNonQuery();
}
/*
* 删除记录后,要重新计算记录数
* 及重新显示记录.
* */
this.ViewState["TotalRecord"]=GetTatolRecordNumber();
setGuide(null);
ShowData();
}
catch(Exception ex)//这是发生错误后所报的错误
{
this.Response.Write("<font color=red>"+ex.Message+"</font>");
}
}
}
}
用.net制作排序、分页解决数据大的问题