还是先看一下效果吧。

怎么样,是不是很酷?
下面一步说明如何实现:
写一个自定义控件,继承自System.Web.UI.WebControl.GridView,然后对其进行扩展。
分页的实现:
重写OnRowCreate方法,对PagerRow进行特殊处理,清空里面的控件,加入自己的控件。首页,尾页,上一页,下一页的做法是,往PagerRow中添加四个LinkButton,CommandName设成"Page",CommandArgument分别设成"First","Last","Prev","Next".相应的Text或者Image可直接使用PagerSettings属性中的数据。
直接跳转页和每页记录条数的实现相对麻烦一些。加入两个DropDownList控件,往里面填充数据,并在此类中处理它们的OnSelectedIndexChange事件,重置PageIndex和PageSize.
排序图标的实现:
同样在OnRowCreate方法中,对HeaderRow进行特殊处理,可根据SortExpression属性找到当前正在进行排序的列,根据SortDirection属性得到排序的顺序,根据这两个属性往特定的列添加特定的图标。
滚动条的实现:
重写RenderContents方法,改变原有的HTML流布局。如果不重写,原来的布局如下:
<Table>//-->GridView

<tr>//-->PagerRow,当PagerPosition设成Top或TopAndBottom的时候,这一行才会出现

</tr>

<tr>//-->HeaderRow

</tr>

<tr>//-->DataRow

</tr>

............

<tr>//-->DataRow

</tr>

<tr>//-->FooterRow

</tr>

<tr>//-->PagerRow(Bottom || TopAndBottom时出现)

</Table>


重写RenderContents的目的就是把整个GridView分隔成三(两)个Table,第一和第三个Table中放PagerRow部分,中间一个Table放在DIV中,固定DIV的高度,使其出现滚动条,对HeaderRow进行特殊处理,使其不会随滚动条的滚动而消失(方法是:style="top:expression(this.parentNode.parentNode.scrollTop);").然后再用一个Table把这三个Table包起来。重写后布局如下:
<Table>

<tr>

<td>

<Table>PagerRow</Table>

</td>

<tr>

<tr>

<td>

<DIV>

<Table>DataRow && FooterRow</Table>

</DIV>

</td>

</tr>

<tr>

<td>

<Table>PagerRow</Table>

</td>

</tr>

</Table>



接下来说一下具体实现:
1、新建一个Web Control Library类型的工程,命名为myControls,添加一个类myGridView.cs:代码如下:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Collections;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
using System.ComponentModel;

namespace CRM2006.GridView

...{

/**//// <summary>
/// Summary description for myGridView
/// </summary>
///
public class CrmGV : System.Web.UI.WebControls.GridView

...{
//private Unit _divheight;
//private int _offset;
private bool isPagerCreated = false;
public CrmGV()

...{
}
[
Description("是否启用自定义分页功能"),
Category("分页"), DefaultValue("false"),Themeable(true)
]
public bool AllowCustomerPagerSettings

...{
get

...{
object o = ViewState["AllowCustomerPagerSettings"];
return (o != null ? (bool)o : false);
}
set

...{
ViewState["AllowCustomerPagerSettings"] = value;
}
}
[Localizable(true), DefaultValue("Current page:"), Themeable(true)]
public string CurrentPageText

...{
get

...{
object o = ViewState["CurrentPageText"];
return (o != null ? o.ToString() : "Current page:");
}
set

...{
ViewState["CurrentPageText"] = value;
}
}
[Localizable(true), DefaultValue("Jump to page"), Themeable(true)]
public string JumpToPageText

...{
get

...{
object o = ViewState["JumpToPageText"];
return (o != null ? o.ToString() : "Jump to page");
}
set

...{
ViewState["JumpToPageText"] = value;
}
}
[Localizable(true), DefaultValue("Display{0}records per page"), Themeable(true)]
public string RecordCountPerPage

...{
get

...{
object o = ViewState["RecordCountPerPage"];
return (o != null ? o.ToString() : "Display{0}records per page");
}
set

...{
ViewState["RecordCountPerPage"] = value;
}
}
[Description("The height of DIV element"), Themeable(true)]
public virtual Unit DIVHeight

...{
get

...{
object o = ViewState["DIVHeight"];
return new Unit(o.ToString());
}
set

...{
ViewState["DIVHeight"] = value;
}
}
[Description("Image Url for sort ascending"),Themeable(true), Editor("System.Web.UI.Design.UrlEditor", typeof(System.Drawing.Design.UITypeEditor))]//Editro特性:指定用以改变属性的编辑器
public string SortAscImageUrl

...{
get

...{
object o = ViewState["SortImageAsc"];
return (o != null ? o.ToString() : "");
}
set

...{
ViewState["SortImageAsc"] = value;
}
}
[Description("Image Url for sort descending"),Themeable(true), Editor("System.Web.UI.Design.UrlEditor", typeof(System.Drawing.Design.UITypeEditor))]//Editro特性:指定用以改变属性的编辑器
public string SortDescImageUrl

...{
get

...{
object o = ViewState["SortImageDesc"];
return (o != null ? o.ToString() : "");
}
set

...{
ViewState["SortImageDesc"] = value;
}
}
[Description("OffSet Value of Head Row"), DefaultValue(4), Themeable(true)]
public int OffSet

...{
get

...{
object o = ViewState["OffSet"];
return Convert.ToUInt16(o);
}
set

...{
if (value <= 1)
ViewState["OffSet"] = 1;
else
ViewState["OffSet"] = value;
}
}
protected override void OnRowCreated(GridViewRowEventArgs e)

...{
if (e.Row.RowType == DataControlRowType.Pager)

...{
if (AllowCustomerPagerSettings)

...{
CreateCustomerPager(e.Row);
}

}
else

...{
if (e.Row.RowType == DataControlRowType.Header)

...{
DisplaySortOrderImages(e.Row);
}
}
base.OnRowCreated(e);
}
protected override void OnSorting(GridViewSortEventArgs e)

...{
base.OnSorting(e);
isPagerCreated = false;
}

private void CreateCustomerPager(GridViewRow pager)

...{
pager.Controls[0].Controls.Clear();
Table tb = new Table();
tb.Style.Add("width", "100%");
TableRow row=new TableRow();
pager.Controls[0].Controls.Add(tb);
tb.Rows.Add(row);
TableCell firstCell = new TableCell();
TableCell secCell = new TableCell();
TableCell tmpCell = new TableCell();
firstCell.Attributes["Align"] = "left";
secCell.Attributes["Align"]="right";
row.Cells.Add(firstCell);
row.Cells.Add(secCell);


tb = new Table();
firstCell.Controls.Add(tb);
row = new TableRow();
tb.Rows.Add(row);

LinkButton lnk = new LinkButton();
Label lbl = new Label();
Image img = new Image();

if (PageIndex != 0)

...{
//First
tmpCell = new TableCell();
tmpCell.Attributes["vAlign"] = "middle";
lnk.CommandArgument = "First";
lnk.CommandName = "Page";
lnk.CausesValidation = false;
if (PagerSettings.FirstPageImageUrl == String.Empty || PagerSettings.FirstPageImageUrl == null)
lnk.Text = (PagerSettings.FirstPageText == String.Empty || PagerSettings.FirstPageText == null ? "First" : PagerSettings.FirstPageText);
else

...{
img.ImageUrl = PagerSettings.FirstPageImageUrl;
lnk.Text = "";
lnk.Controls.Add(img);
}
tmpCell.Controls.Add(lnk);
row.Cells.Add(tmpCell);

//Preview
lnk = new LinkButton();
tmpCell = new TableCell();
tmpCell.Attributes["vAlign"] = "middle";
img = new Image();
lnk.CommandArgument = "Prev";
lnk.CommandName = "Page";
lnk.CausesValidation = false;
if (PagerSettings.PreviousPageImageUrl == String.Empty || PagerSettings.PreviousPageImageUrl == null)
lnk.Text = (PagerSettings.PreviousPageText == String.Empty || PagerSettings.PreviousPageText == null ? "Prev" : PagerSettings.PreviousPageText);
else

...{
img.ImageUrl = PagerSettings.PreviousPageImageUrl;
lnk.Text = "";
lnk.Controls.Add(img);
}
tmpCell.Controls.Add(lnk);
row.Cells.Add(tmpCell);
}

//Current
tmpCell = new TableCell();
tmpCell.Attributes["vAlign"] = "middle";
if (CurrentPageText == "" || CurrentPageText.IndexOf("{0}") <= 0)

...{
lbl.Text = "Current Page: " + Convert.ToString(PageIndex+1)+"/"+PageCount.ToString()+" ";
}
else

...{
lbl.Text = string.Format(CurrentPageText, " " + Convert.ToString(PageIndex + 1) + "/" + PageCount.ToString() + " ");
}
tmpCell.Controls.Add(lbl);
row.Cells.Add(tmpCell);

if (PageIndex != PageCount - 1)

...{
//Next
lnk = new LinkButton();
tmpCell = new TableCell();
tmpCell.Attributes["vAlign"] = "middle";
img = new Image();
lnk.CommandArgument = "Next";
lnk.CommandName = "Page";
lnk.CausesValidation = false;
if (PagerSettings.NextPageImageUrl == String.Empty || PagerSettings.NextPageImageUrl == null)
lnk.Text = (PagerSettings.NextPageText == String.Empty || PagerSettings.NextPageText == null ? "Next" : PagerSettings.NextPageText);
else

...{
img.ImageUrl = PagerSettings.NextPageImageUrl;
lnk.Text = "";
lnk.Controls.Add(img);
}
tmpCell.Controls.Add(lnk);
row.Cells.Add(tmpCell);

//Last
lnk = new LinkButton();
tmpCell = new TableCell();
tmpCell.Attributes["vAlign"] = "middle";
img = new Image();
lnk.CommandArgument = "Last";
lnk.CommandName = "Page";
lnk.CausesValidation = false;
if (PagerSettings.LastPageImageUrl == String.Empty || PagerSettings.LastPageImageUrl == null)
lnk.Text = (PagerSettings.LastPageText == String.Empty || PagerSettings.LastPageText == null ? "Last" : PagerSettings.LastPageText);
else

...{
img.ImageUrl = PagerSettings.LastPageImageUrl;
lnk.Text = "";
lnk.Controls.Add(img);
}
tmpCell.Controls.Add(lnk);
row.Cells.Add(tmpCell);
}

//Jump To
DropDownList ddl = new DropDownList();
ddl.AutoPostBack = true;
//if (!isPagerCreated)
ddl.SelectedIndexChanged += new EventHandler(CurrentPageIndexChange);
tmpCell = new TableCell();
tmpCell.Attributes["vAlign"] = "middle";
ListItem item = new ListItem();
string[] tmp;
for (int i = 0; i < PageCount; i++)

...{
item= new ListItem(Convert.ToString(i + 1), Convert.ToString(i + 1));
ddl.Items.Add(item);
}
ddl.SelectedValue = Convert.ToString(PageIndex+1);
if (JumpToPageText == string.Empty || JumpToPageText == null)

...{
lbl = new Label();
lbl.Text = "Jump To Page:";
tmpCell.Controls.Add(lbl);
tmpCell.Controls.Add(ddl);
}
else

...{
tmp = (String.Format(JumpToPageText, "*")).Split('*');
if (tmp.Length >= 2)

...{
lbl = new Label();
lbl.Text = tmp[0];
tmpCell.Controls.Add(lbl);
tmpCell.Controls.Add(ddl);
lbl = new Label();
lbl.Text = tmp[1];
tmpCell.Controls.Add(lbl);
}
else

...{
lbl = new Label();
lbl.Text = JumpToPageText;
tmpCell.Controls.Add(lbl);
tmpCell.Controls.Add(ddl);
}
}
row.Cells.Add(tmpCell);

tb = new Table();
row = new TableRow();
tb.Rows.Add(row);
secCell.Controls.Add(tb);
//PageSize

ddl = new DropDownList();
tmpCell = new TableCell();
tmpCell.Attributes["vAlign"] = "middle";
ddl.AutoPostBack = true;
item = new ListItem("5", "5");
ddl.Items.Add(item);
item = new ListItem("10", "10");
ddl.Items.Add(item);
item = new ListItem("20", "20");
ddl.Items.Add(item);
item = new ListItem("30", "30");
ddl.Items.Add(item);
item = new ListItem("50", "50");
ddl.Items.Add(item);
lbl = new Label();
try

...{
ddl.SelectedValue = this.PageSize.ToString();
}
catch

...{
ddl.SelectedValue = "10";
}
ddl.SelectedIndexChanged += new EventHandler(ddl_SelectedIndexChanged);
if (RecordCountPerPage == string.Empty || RecordCountPerPage == null)

...{
RecordCountPerPage = "Display{0}records per page";
}
tmp = (String.Format(RecordCountPerPage, "*")).Split('*');
if (tmp.Length >= 2)

...{
lbl = new Label();
lbl.Text = tmp[0];
tmpCell.Controls.Add(lbl);
tmpCell.Controls.Add(ddl);
lbl = new Label();
lbl.Text = tmp[1];
tmpCell.Controls.Add(lbl);
}
else

...{
lbl = new Label();
lbl.Text = RecordCountPerPage;
tmpCell.Controls.Add(lbl);
tmpCell.Controls.Add(ddl);
}
row.Cells.Add(tmpCell);
isPagerCreated = true;
}
private void CurrentPageIndexChange(object sender, EventArgs e)

...{
this.PageIndex = int.Parse(((DropDownList)sender).SelectedValue)-1;
isPagerCreated = false;
}
private void DisplaySortOrderImages(GridViewRow dgItem)

...{
for (int i = 0; i < dgItem.Cells.Count; i++)

...{
if (dgItem.Cells[i].Controls.Count > 0 && dgItem.Cells[i].Controls[0] is LinkButton)

...{
string columnExpression = ((LinkButton)dgItem.Cells[i].Controls[0]).CommandArgument;
if (columnExpression == SortExpression)

...{
string sortImgLoc = (SortDirection == SortDirection.Ascending ? SortAscImageUrl : SortDescImageUrl);
Image imgSortDirection = new Image();
imgSortDirection.ImageUrl = sortImgLoc;
dgItem.Cells[i].Controls.Add(imgSortDirection);
break;
}
}
}
}
private void ddl_SelectedIndexChanged(object sender,EventArgs e)

...{
this.PageSize = int.Parse(((DropDownList)sender).SelectedValue);
this.PageIndex = 0;
isPagerCreated = false;
}
protected override void RenderContents(HtmlTextWriter writer)

...{
StringWriter sw = new StringWriter();
HtmlTextWriter hw = new HtmlTextWriter(sw);
base.RenderContents(hw);
string strHtml = sw.ToString();

string strTable = getTable(strHtml);
bool bHeadPager = this.PagerSettings.Position == PagerPosition.TopAndBottom || this.PagerSettings.Position == PagerPosition.Top;
strHtml = "<table border='0' cellspacing='0' cellpadding='0'><tr><td>";
string strPager = "";
for (int i = 0; i < this.Controls[0].Controls.Count; i++)

...{
GridViewRow row = (GridViewRow)this.Controls[0].Controls[i];
row.Visible = true;
StringWriter tmpsw = new StringWriter();
HtmlTextWriter tmphw = new HtmlTextWriter(tmpsw);
row.RenderControl(tmphw);
if (i == 0)

...{
if (row.RowType == DataControlRowType.Pager)

...{
strPager = tmpsw.ToString();
if (this.DIVHeight.Value > 0)
strHtml += "<table border='0' cellspacing='0' cellpadding='0' width='100%'>" + strPager + "</table></td></tr><tr><td><div style='height:" + this.DIVHeight.ToString() + ";overflow-y:auto;'>" + strTable;
else
strHtml += "<table border='0' cellspacing='0' cellpadding='0' width='100%'>" + strPager + "</table></td></tr><tr><td><div style='overflow-y:auto;'>" + strTable;
isPagerCreated = true;
}
else

...{
if (this.DIVHeight.Value > 0)
strHtml += "<div style='overflow-Y:auto;height:" + this.DIVHeight.ToString() + ";'>" + strTable;
else
strHtml += "<div style='overflow-Y:auto;'>" + strTable;
if (row.RowType == DataControlRowType.Header)

...{
string HeadStr = tmpsw.ToString();
int pos = HeadStr.IndexOf("style="");
if (pos > 0)

...{
HeadStr = HeadStr.Insert(pos + 7, "position:relative;top:expression(parentNode.parentNode.scrollTop-" + this.OffSet + ");");
}
else

...{
HeadStr = HeadStr.Insert(3, "style="position:relative;top:expression(parentNode.parentNode.scrollTop-" + this.OffSet + ");");
}
strHtml += HeadStr;
}
else
strHtml += tmpsw.ToString();
}
}
else

...{
if (i != this.Controls[0].Controls.Count - 1)

...{
if (row.RowType == DataControlRowType.Header)

...{
string HeadStr = tmpsw.ToString();
int pos = HeadStr.IndexOf("style="");
if (pos > 0)

...{
HeadStr = HeadStr.Insert(pos + 7, "position:relative;top:expression(parentNode.parentNode.scrollTop-1);");
}
else

...{
HeadStr = HeadStr.Insert(3, "style="position:relative;top:expression(parentNode.parentNode.scrollTop-1);");
}
strHtml += HeadStr;
}
else
strHtml += tmpsw.ToString();
}
else

...{
if (row.RowType == DataControlRowType.Pager)

...{
strHtml += "</table></div></td></tr><tr><td><table border='0' cellspacing='0' cellpadding='0' width='100%'>" + tmpsw.ToString();
}
else

...{
strHtml += tmpsw.ToString();
}
}
}
}
strHtml += "</table></td></tr></table>";
writer.Write(strHtml);
isPagerCreated = false;
}
private string getTable(string _html)

...{
int posStart, posEnd;
posStart = _html.IndexOf("<table", 0);
posEnd = _html.IndexOf(">", posStart);
return(_html.Substring(posStart,posEnd-posStart+1));
}
}
}

使用方法:
引用:可以把这个工程编译成DLL后,在其他工程中引用此DLL,也可以把这个工程同别的工程放到同一解决方案中,直接引用此工程。
设计:
往页面中添加控件的两种方法:
1、Toolbox右键--choose item(s)---.Net Components---browse,选中编译好的myGridView.dll,就会在Toobox出现图标,可直接拖到页面上。
2、在页面的Source页里添加
<%@ Register Assembly="myControls" Namespace="myControls" TagPrefix="control" %>
就可以在页面中敲入<control:myGridView ID="" runat="server"></control:myGridView>了.