1. 引言 在ASP.NET中DataList可以實現(xiàn)數(shù)據(jù)展示,,我們可以通過定制其模版實現(xiàn)豐富的格式,,但是美中不足的時DataList默認(rèn)情況下不支持分頁,,我們當(dāng)然可以編寫一個用戶控件以實現(xiàn)分頁功能,但是這種方案仍然不是很好,,我們希望像使用普通ASP.NET服務(wù)器端控件一樣,,只需要放置一個DataList并設(shè)置分頁樣式就可以輸出分頁鏈接。
在上次任務(wù)中我們創(chuàng)建了DataPager類將創(chuàng)建分頁的操作從GridView分離出來,,本次任務(wù)將嘗試重用DataPager類為DataList增加分頁特性,。
2. 分析 開發(fā)自定義GridView控件時,可以通過向控件中加入具有特定CommandName的按鈕實現(xiàn)分頁,,但是對于DataList卻不適用,,因為DataList不能接收到客戶端的回發(fā)事件,這也是DataList類和GridView類的一個區(qū)別—DataList類沒有實現(xiàn)IPostBackEventHandler接口,。為了能夠使DataList接收客戶端回發(fā)并觸發(fā)分頁事件,,需要使自定義DataList實現(xiàn)IPostBackEventHandler接口,并使用自定義事件參數(shù)類在觸發(fā)事件時傳遞頁碼信息,。
IPostBackEventHandler接口定義了ASP.NET服務(wù)器控件為處理回發(fā)事件而必須實現(xiàn)的方法,,它的成員只有一個方法:
void RaisePostBackEvent(string eventArgument) 該方法由類實現(xiàn)時,使服務(wù)器控件能夠處理將窗體發(fā)送到服務(wù)器時引發(fā)的事件,。
接下來需要考慮如何在客戶端引起回發(fā)事件,,即怎樣生成回發(fā)腳本。這里使用到了ClientScriptManager類,,該類作為Page類的一個屬性ClientScript出現(xiàn),,通過調(diào)用該類的GetPostBackClientHyperlink方法生成客戶端腳本以引起回發(fā),該方法有兩個形式的重載:
GetPostBackClientHyperlink (Control, String) 獲取一個引用,,并在其開頭附加 javascript:,,可以在客戶端事件中使用該引用,并將該引用與指定的事件參數(shù)一起使用,,以便回發(fā)到指定控件的服務(wù)器,。
GetPostBackClientHyperlink (Control, String, Boolean) 獲取一個引用,并在其開頭附加 javascript:,,該引用可用于在客戶端事件中回發(fā)到指定控件的服務(wù)器,,回發(fā)時使用指定的事件參數(shù)和一個指示是否為事件驗證注冊該回發(fā)的布爾值。
其中第一個參數(shù)指明了處理回發(fā)的服務(wù)器控件,,第二個參數(shù)代表傳遞給服務(wù)器控件的參數(shù),,第三個參數(shù)代表是否驗證注冊回發(fā)事件。
接下來編寫實現(xiàn)代碼。
3. 實現(xiàn) 3.1 創(chuàng)建DataListPager類,,該類繼承自DataPager類實現(xiàn)了為分頁鏈接添加回發(fā)腳本操作:
public class DataListPager : DataPager { public DataListPager(PagerSettings setting, int pageIndex, int recordCount, int pageSize, DataList dal) : base(setting, pageIndex, recordCount, pageSize) { LinkButton btn = null; int _pageCount = recordCount % pageSize == 0 ? recordCount / pageSize : recordCount / pageSize + 1; int index;
foreach (Control control in this.Controls) { if (control is LinkButton) { btn = (LinkButton)control;
if (btn.Enabled) { string argvalue = btn.CommandArgument;
bool isInt = int.TryParse(argvalue, out index); string arg = string.Empty; if (isInt) { index--; } else { switch (argvalue) { case Constant.FIRST_PAGE: index = 0; break; case Constant.PREV_PAGE: index = pageIndex - 1 < 0 ? 0 : pageIndex - 1; break; case Constant.NEXT_PAGE: index = pageIndex + 1 > _pageCount - 1 ? _pageCount - 1 : pageIndex + 1; break; case Constant.LAST_PAGE: index = _pageCount - 1; break; } }
arg = Constant.PAGE_ARGUMENT + Constant.ARGUMENT_SPLITTER + index; btn.Attributes.Add(HtmlTextWriterAttribute.Href.ToString(), dal.Page.ClientScript.GetPostBackClientHyperlink(dal, arg)); }
} } } } 3.2 創(chuàng)建DataList類,,繼承自默認(rèn)的DataList類并實現(xiàn)IPostBackEventHandler接口:
[ToolboxData(@"<{0}:DataList runat='server'></{0}:DataList>")] [ParseChildren(true)] [PersistChildren(false)] public class DataList : System.Web.UI.WebControls.DataList, IPostBackEventHandler { } 3.3 定義DataList屬性,保存分頁設(shè)置信息:
public int RecordCount { get { object o = ViewState["RecordCount"];
return o == null ? 0 : Convert.ToInt32(o); } set { ViewState["RecordCount"] = value; } }
public virtual int PageIndex { get { object o = ViewState["PageIndex"];
return o == null ? 0 : Convert.ToInt32(o); } set { ViewState["PageIndex"] = value; } }
[DefaultValue(10)] public virtual int PageSize { get { object o = ViewState["PageSize"];
return o == null ? 10 : Convert.ToInt32(o); } set { ViewState["PageSize"] = value; } }
private PagerSettings _settings;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [PersistenceMode(PersistenceMode.InnerProperty)] public PagerSettings PagerSettings { get { if (_settings == null) _settings = new PagerSettings(); if (base.IsTrackingViewState) ((IStateManager)_settings).TrackViewState();
return this._settings; } }
public bool EnablePaging { get { object o = ViewState["EnablePaging"];
return o == null ? false : Convert.ToBoolean(o); } set { ViewState["EnablePaging"] = value; } } 3.4 創(chuàng)建自定義事件類,,保存新頁碼:
public class DataListPageEventArgs : EventArgs { public int NewPageIndex { get; set; } } 3.5 在DataList類中創(chuàng)建事件和輔助方法:
public event EventHandler<DataListPageEventArgs> PageIndexChanging; protected virtual void OnPageIndexChanging(object sender, DataListPageEventArgs e) { if (PageIndexChanging != null) { PageIndexChanging(sender, e); } } 3.6 編寫RenderContent方法,,該方法是實現(xiàn)了分頁的核心操作,通過實例化DataListPager類的實例,,將觸發(fā)回發(fā)操作的鏈接加入到當(dāng)前DataList中:
protected override void RenderContents(HtmlTextWriter writer) { this.RenderBeginTag(writer);
if (EnablePaging) { Table table = new Table(); TableRow row = new TableRow(); table.Rows.Add(row); TableCell cell = new TableCell();
row.RenderBeginTag(writer); cell.RenderBeginTag(writer);
base.RenderContents(writer);
cell.RenderEndTag(writer); row.RenderEndTag(writer);
TableRow rowpager = new TableRow();
DataListPager pager = new DataListPager(PagerSettings, PageIndex, RecordCount, PageSize, this);
rowpager.Cells.Add(pager);
rowpager.RenderBeginTag(writer);
pager.RenderControl(writer);
rowpager.RenderEndTag(writer);
} else { base.RenderContents(writer); }
this.RenderEndTag(writer); } 3.7 編寫IPostEventHandler接口中RaisePostBackEvent方法的實現(xiàn),,判斷當(dāng)前事件參數(shù)并觸發(fā)換頁事件:
public void RaisePostBackEvent(string eventArgument) { string[] args = eventArgument.Split(Constant.ARGUMENT_SPLITTER);
if (args == null || args.Length < 1) return;
string name = args[0];
if (name == Constant.PAGE_ARGUMENT) { int index = 0; string argvalue = args[1]; bool isInt = int.TryParse(argvalue, out index);
if (isInt) { DataListPageEventArgs arg = new DataListPageEventArgs(); arg.NewPageIndex = index;
OnPageIndexChanging(this, arg); } } } 3.8 重寫SaveViewState和LoadViewState方法定義保存和讀取視圖狀態(tài)方法:
protected override object SaveViewState() { object o = base.SaveViewState(); object osetting = ((IStateManager)PagerSettings).SaveViewState(); Pair p = new Pair(o, osetting);
return p; }
protected override void LoadViewState(object savedState) { if (savedState != null) { Pair p = (Pair)savedState; base.LoadViewState(p.First); ((IStateManager)PagerSettings).LoadViewState(p.Second); } else { base.LoadViewState(null); } } 3.9 在網(wǎng)站中創(chuàng)建測試頁,聲明并定義自定義DataList:
<cc:DataList ID="dalData" runat="server" EnablePaging="true" PageSize="10" OnPageIndexChanging="dalData_PageIndexChanging" PagerSettings-FirstPageText="????"> <ItemTemplate> <table class="data" cellpadding="0" cellspacing="1" border="0"> <tr> <td><asp:Label ID="lblId" runat="server" Text='<%#Eval("Id") %>'></asp:Label></td> <td><asp:Label ID="lblName" runat="server" Text='<%#Eval("Name") %>'></asp:Label></td> </tr> </table> </ItemTemplate> </cc:DataList> 3.10 在后置代碼中編寫B(tài)indData方法加載數(shù)據(jù),,并且在頁面不是回發(fā)時調(diào)用此方法顯示數(shù)據(jù):
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) this.BindData(); }
private void BindData() { DataTable table = new DataTable();
DataColumn col = new DataColumn("Id"); table.Columns.Add(col); col = new DataColumn("Name"); table.Columns.Add(col);
for (int i = dalData.PageIndex * dalData.PageSize; i < dalData.PageIndex * dalData.PageSize+dalData.PageSize; i++) { DataRow row = table.NewRow(); row[0] = i; row[1] = "人員 " + i;
table.Rows.Add(row); }
dalData.DataSource = table; dalData.RecordCount = 30; dalData.DataBind(); } 3.11 編寫DataList的切換頁事件,,將新的頁碼索引賦值給DataList并執(zhí)行數(shù)據(jù)綁定: protected void dalData_PageIndexChanging(object sender, DataListPageEventArgs e) { dalData.PageIndex = e.NewPageIndex; this.BindData(); } 3.12 在瀏覽器中預(yù)覽效果:
4. 總結(jié) 在本次任務(wù)中,通過為LinkButton加入了JavaScript腳本使得在客戶端點擊時可以引起回發(fā)操作,,這是通過ClientScriptManager類的GetPostBackClientHyperlink方法實現(xiàn)的,。引起提交后,為了能夠在服務(wù)器端處理回發(fā)事件,,在自定義DataList控件中實現(xiàn)了IPostBackEventHandler接口并在實現(xiàn)方法中調(diào)用了自定義頁切換事件,,使開發(fā)人員能夠根據(jù)新頁碼進行數(shù)據(jù)綁定??梢钥吹?,現(xiàn)在DataList和GridView都已經(jīng)實現(xiàn)分頁了,但是從某種意義上來說,,這個解決方案還不夠優(yōu)雅(經(jīng)常被Java程序員拿來說事的一個詞-_-!!),,您可以自行加以改良。
全部源碼下載
本系列文章PDF版本下載
來源:http://www.cnblogs.com/holywolf
|