一、控件也是類
【效果】
【操作步驟】
1、 新建網(wǎng)站W(wǎng)eb
2、 添加類CustomDataList.cs(系統(tǒng)會(huì)提示你把類建在App_Code文件夾中),代碼如下:
using System; using System.Collections; using System.Text.RegularExpressions; using System.Web.UI; using System.Web.UI.WebControls; namespace WestGarden.Web { public class CustomDataList : DataList { } } |
3、在Default.aspx中注冊(cè)并添加類CustomDataList,代碼如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <%@ Register Namespace="WestGarden.Web" TagPrefix="cc" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>具有分頁(yè)功能的自定義DataList控件</title> </head> <body> <form id="form1" runat="server"> <div> <cc:CustomDataList ID="CustomDataList1" runat="server" RepeatColumns="2"> <ItemTemplate> <table border="1"> <tr> <td><%# Eval("Number")%></td> </tr> </table> </ItemTemplate> </cc:CustomDataList> </div> </form> </body> </html> |
4、在Default.aspx.cs中創(chuàng)建符合IList接口的表格示例數(shù)據(jù),并做為數(shù)據(jù)源與CustomDataList1綁定,代碼如下:
using System; using System.Data; using System.Collections; using System.Web.UI.WebControls; public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { CustomDataList1.DataSource = CreateDataSource(); CustomDataList1.DataBind(); } //創(chuàng)建符合IList接口的表格示例數(shù)據(jù) IList CreateDataSource() { DataTable dt = new DataTable(); DataRow dr; dt.Columns.Add(new DataColumn("Number", typeof(Int32))); for (int i = 0; i <10; i++) { dr = dt.NewRow(); dr["Number"] = i; dt.Rows.Add(dr); } DataView dv = new DataView(dt); return dv; } } |
5、在瀏覽器中查看運(yùn)行結(jié)果如效果圖示。
【說(shuō)明】
1、很多時(shí)候,怎么說(shuō)都說(shuō)不清楚的事情,做出來(lái),什么都不說(shuō),大家也就都明白了。在這里,大家可以清清楚楚地看到,所謂的控件,完完全全地是個(gè)類。所謂的類,其實(shí)就是具有一定功能,可以進(jìn)行某類操作的程序塊,這個(gè)程序塊可以有變量、屬性、可以有函數(shù)、代碼,當(dāng)然也可以有窗體、界面。
2、為了演示方便,我們沒(méi)有從數(shù)據(jù)庫(kù)中讀取數(shù)據(jù),而是做了一個(gè)函數(shù),動(dòng)態(tài)創(chuàng)建一個(gè)具有Ilist接口的簡(jiǎn)單的表格數(shù)據(jù)。
3、DataList的模板和Repeater差不多,還是手工做,方便一些。和Repeater相比,主要多了一個(gè)RepeatColumns屬性,在電子商務(wù)系統(tǒng)中,用來(lái)展示商品列表比較方便,但默認(rèn)沒(méi)有分頁(yè)功能,可以通過(guò)本例,自定義實(shí)現(xiàn)。
二、呈現(xiàn)
【效果】
【操作步驟】
1、CustomDataList.cs中改寫(xiě)基類的Render()函數(shù)來(lái)實(shí)現(xiàn),完整代碼如下:
using System; using System.Collections; using System.Text.RegularExpressions; using System.Web.UI; using System.Web.UI.WebControls; namespace WestGarden.Web { public class CustomDataList : DataList { protected const string HTML1 = "<table border=1><tr><td colspan=2>"; protected const string HTML2 = "</td></tr><tr><td class=paging align=left>"; protected const string HTML3 = "</td><td align=right class=paging>"; protected const string HTML4 = "</td></tr></table>"; private static readonly Regex RX = new Regex(@"^&page=\d+", RegexOptions.Compiled); private const string LINK_PREV = "<a href=?page={0}>< 上一頁(yè)</a>"; private const string LINK_MORE = "<a href=?page={0}>下一頁(yè) ></a>"; private const string KEY_PAGE = "page"; private const string COMMA = "?"; private const string AMP = "&"; private int currentPageIndex = 0; override protected void Render(HtmlTextWriter writer) { string query = ""; if (!DesignMode) { query = Context.Request.Url.Query.Replace(COMMA, AMP); query = RX.Replace(query, string.Empty); } writer.Write(HTML1); base.Render(writer); writer.Write(HTML2); writer.Write(string.Format(LINK_PREV, (currentPageIndex - 1) + query)); writer.Write(HTML3); writer.Write(string.Format(LINK_MORE, (currentPageIndex + 1) + query)); writer.Write(HTML4); } } } |
2、在瀏覽器中查看運(yùn)行結(jié)果如效果圖示。
【說(shuō)明】
1、這段代碼的主要功能是呈現(xiàn)一個(gè)二行二列的表格,為了顯示得清晰一些,設(shè)置了這個(gè)表格的邊框?yàn)?,從效果圖可以看出,原來(lái)DataList顯示的內(nèi)容,顯示在表格的第一行,合并單元格后的單元格中,第二行的兩個(gè)單元格,分別顯示“<上一頁(yè)”和“下一頁(yè)>”。
2、這兩個(gè)單元格內(nèi)的文字,分別加了個(gè)鏈接參數(shù)?page={0},page的值暫時(shí)由默認(rèn)的當(dāng)前頁(yè)號(hào)加1或減1獲得。
3、使用類Regex是根據(jù)正則表達(dá)式“&page=\d+”獲取并替代網(wǎng)址中的參數(shù)page,具體用法可參閱MSDN的相關(guān)內(nèi)容。
4、if (!DesignMode)是判斷當(dāng)前是否在設(shè)計(jì)時(shí)狀態(tài),以決定{}中的語(yǔ)句是否執(zhí)行。因?yàn)閧}中的語(yǔ)句需要從地址中獲取參數(shù)page后面的字符串query,這個(gè)query在設(shè)計(jì)時(shí)是未知數(shù),會(huì)影響到控件內(nèi)容的呈現(xiàn),所以,在設(shè)計(jì)時(shí)不執(zhí)行,而并不影響實(shí)際使用。
三、屬性
【效果】
【操作步驟】
1、CustomDataList.cs中為自定義控件添加屬性,并改寫(xiě)屬性DataSource、函數(shù) OnDataBinding(),完整代碼如下:
using System; using System.Collections; using System.Text.RegularExpressions; using System.Web.UI; using System.Web.UI.WebControls; namespace WestGarden.Web { public class CustomDataList : DataList { protected const string HTML1 = "<table border=1><tr><td colspan=2>"; protected const string HTML2 = "</td></tr><tr><td class=paging align=left>"; protected const string HTML3 = "</td><td align=right class=paging>"; protected const string HTML4 = "</td></tr></table>"; private static readonly Regex RX = new Regex(@"^&page=\d+", RegexOptions.Compiled); private const string LINK_PREV = "<a href=?page={0}>< 上一頁(yè)</a>"; private const string LINK_MORE = "<a href=?page={0}>下一頁(yè) ></a>"; private const string KEY_PAGE = "page"; private const string COMMA = "?"; private const string AMP = "&"; private int pageSize = 10; private int currentPageIndex=0; private int itemCount; private IList dataSource; protected string emptyText; public int PageSize { get { return pageSize; } set { pageSize = value; } } protected int PageCount { get { return (ItemCount - 1) / pageSize; } } virtual protected int ItemCount { get { return itemCount; } set { itemCount = value; } } virtual public int CurrentPageIndex { get { return currentPageIndex; } set { currentPageIndex = value; } } public string EmptyText { set { emptyText = value; } } override public object DataSource { set { try { dataSource = (IList)value; ItemCount = dataSource.Count; } catch { dataSource = null; ItemCount = 0; } } } override protected void OnDataBinding(EventArgs e) { int start = CurrentPageIndex * pageSize; int size = Math.Min(pageSize, ItemCount - start); IList pageList = new ArrayList(); for (int i = 0; i < size; i++) pageList.Add(dataSource[start + i]); base.DataSource = pageList; base.OnDataBinding(e); } override protected void Render(HtmlTextWriter writer) { if (ItemCount == 0) { writer.Write(emptyText); return; } string query = ""; if (!DesignMode) { query = Context.Request.Url.Query.Replace(COMMA, AMP); query = RX.Replace(query, string.Empty); } writer.Write(HTML1); base.Render(writer); writer.Write(HTML2); writer.Write(string.Format(LINK_PREV, (currentPageIndex - 1) + query)); writer.Write(HTML3); writer.Write(string.Format(LINK_MORE, (currentPageIndex + 1) + query)); writer.Write(HTML4); } } } |
2、Default.aspx中設(shè)置CustomDataList1的屬性PageSize="4" EmptyText="No Data found.",這兩個(gè)屬性可以屬性窗口中設(shè)置,如圖示:
3、在瀏覽器中查看運(yùn)行結(jié)果如效果圖示。
【說(shuō)明】
1、CustomDataList分頁(yè)的主要邏輯是,改寫(xiě)DataList的DataSource屬性,在設(shè)置數(shù)據(jù)源CustomDataList1.DataSource =CreateDataSource();時(shí),用Ilist類指針dataSource (也就是俗稱的接口)接收過(guò)來(lái),同時(shí),獲取數(shù)據(jù)源中數(shù)據(jù)項(xiàng)的個(gè)數(shù)ItemCount,然后,改寫(xiě)DataList的DataBind()函數(shù),在函數(shù)中通過(guò)當(dāng)前頁(yè)號(hào)CurrentPageIndex(當(dāng)前頁(yè)號(hào)初始值為0,在后面,點(diǎn)擊“上一頁(yè)”“下一頁(yè)”時(shí)需要重新設(shè)置)與屬性中設(shè)置的每頁(yè)的數(shù)據(jù)項(xiàng)個(gè)數(shù)pageSize獲取起始數(shù)據(jù)項(xiàng)int start = CurrentPageIndex * pageSize;。因?yàn)樽詈笠豁?yè)數(shù)據(jù)項(xiàng)的個(gè)數(shù)不一定,所以該頁(yè)的個(gè)數(shù)需要重新確定一下int size =Math.Min(pageSize,ItemCount - start);,有了這兩個(gè)值,就可以把相應(yīng)的數(shù)據(jù)項(xiàng)取出存放在重新定義的IList pageList =newArrayList();中,最后,把這個(gè)pageList做為DataList的數(shù)據(jù)源與DataList綁定。
2、在屬性窗口中設(shè)置屬性,需要刷新一下,在工作區(qū)窗口中把Default.aspx關(guān)閉,再重新打開(kāi)就可以了。
四、事件
【效果】
【操作步驟】
1、在CustomDataList.cs中,添加事件PageIndexChanged
public event DataGridPageChangedEventHandler PageIndexChanged; virtual protected void OnPageIndexChanged(DataGridPageChangedEventArgs e) { if (PageIndexChanged != null) PageIndexChanged(this, e); } |
2、在Default.aspx中設(shè)置事件處理函數(shù)onpageindexchanged="CustomDataList1_PageIndexChanged",這個(gè)設(shè)置也可以在屬性窗口中的事件選項(xiàng)卡中進(jìn)行,如圖示:
3、在Default.aspx.cs中添加代碼,并刪除原來(lái)Page_Load()中的代碼,完整代碼如下:
using System; using System.Data; using System.Collections; using System.Web.UI.WebControls; public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } //創(chuàng)建符合IList接口的表格示例數(shù)據(jù) IList CreateDataSource() { DataTable dt = new DataTable(); DataRow dr; dt.Columns.Add(new DataColumn("Number", typeof(Int32))); for (int i = 0; i <= 10; i++) { dr = dt.NewRow(); dr["Number"] = i; dt.Rows.Add(dr); } DataView dv = new DataView(dt); return dv; } protected void CustomDataList1_PageIndexChanged(object source, DataGridPageChangedEventArgs e) { CustomDataList1.CurrentPageIndex = e.NewPageIndex; CustomDataList1.DataSource = CreateDataSource(); CustomDataList1.DataBind(); } } |
4、在瀏覽器中查看運(yùn)行結(jié)果如效果圖示。
【說(shuō)明】
1、DataGridPageChangedEventHandler是委托,原型為:
publicdelegatevoidDataGridPageChangedEventHandler(Object source,DataGridPageChangedEventArgs e)
C#中的委托,類似于C、C++中的函數(shù)指針,從DataGridPageChangedEventHandler的原型可以看出,它相當(dāng)于是形參為(Object source,DataGridPageChangedEventArgs e),返回值為void的函數(shù)指針。只不過(guò)在C#中,委托被做成了類,是一種數(shù)據(jù)類型,需要實(shí)例化成類變量,才能存放函數(shù)的指針變量。
2、在屬性窗口的事件選項(xiàng)卡中設(shè)置事件處理程序,需要刷新一下,在工作區(qū)窗口中把Default.aspx關(guān)閉,再重新打開(kāi)就可以了。
3、運(yùn)行結(jié)果沒(méi)有數(shù)據(jù)顯示,是因?yàn)槭录⺁ageIndexChanged的事件處理程序沒(méi)有被觸發(fā)。
五、觸發(fā)事件處理程序
【效果】
【操作步驟】
1、CustomDataList.cs中改寫(xiě)DataList的OnLoad()函數(shù),并添加函數(shù)SetPage(),代碼如下:
override protected void OnLoad(EventArgs e) { if (Visible) { string page = Context.Request[KEY_PAGE]; int index = (page != null) ? int.Parse(page) : 0; SetPage(index); } } public void SetPage(int index) { OnPageIndexChanged(new DataGridPageChangedEventArgs(null, index)); } |
3、在瀏覽器中查看運(yùn)行結(jié)果如效果圖示。
【說(shuō)明】
1、觸發(fā)(Raise)事件有很多方式,在這里,重載并修改了DataList的OnLaod()函數(shù),在裝載自定義控件CustomDataList時(shí),讀取地址中的參數(shù)page,并根據(jù)page的值獲取要顯示的頁(yè)號(hào)index (如果page為空的話,就設(shè)為0),并把index交給函數(shù)SetPage(),在SetPage()中調(diào)用OnPageIndexChanged(),進(jìn)而通過(guò)PageIndexChanged(this, e);觸發(fā)了事件處理函數(shù)。因?yàn),事件相?dāng)于C、C++中的函數(shù)指針變量,它的值,在Default.aspx中設(shè)置CustomDataList的事件處理函數(shù)時(shí),就已經(jīng)指向了形參為(objectsource,DataGridPageChangedEventArgs e),返回值為void類型的函數(shù)了。
2、委托我們使用的是現(xiàn)成的不需要聲明的DataGridPageChangedEventHandler,委托要傳遞的參數(shù)變量也是現(xiàn)成的不需要聲明的DataGridPageChangedEventArgs,通過(guò)newDataGridPageChangedEventArgs(null, index),就可以直接給參數(shù)變量賦值并傳遞了。
3、前面,為了強(qiáng)調(diào)顯示效果,我們把“<上一頁(yè)”“下一頁(yè)>”無(wú)條件地顯示了,事實(shí)上,如果頁(yè)號(hào)為0,就不應(yīng)該顯示當(dāng)前頁(yè)“<上一頁(yè)”,而頁(yè)號(hào)為最后一頁(yè)的時(shí)候,如果顯示“下一頁(yè)>”,由于鏈接問(wèn)題,點(diǎn)擊會(huì)出現(xiàn)錯(cuò)誤的。為此,需要在Render(),顯示這兩句之前分別加上條件:
if (currentPageIndex > 0) writer.Write(string.Format(LINK_PREV, (currentPageIndex - 1) + query)); if (currentPageIndex < PageCount) writer.Write(string.Format(LINK_MORE, (currentPageIndex + 1) + query)); |