zoukankan      html  css  js  c++  java
  • 控件也是类——分步实现具有分页功能的自定义DataList控件【附源代码】

    一、控件也是类

    【效果】

    【操作步骤】

    1、  新建网站Web

    2、  添加类CustomDataList.cs(系统会提示你把类建在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中注册并添加类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>具有分页功能的自定义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中创建符合IList接口的表格示例数据,并做为数据源与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();
        }
        //创建符合IList接口的表格示例数据
        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、在浏览器中查看运行结果如效果图示。

    【说明】

    1、很多时候,怎么说都说不清楚的事情,做出来,什么都不说,大家也就都明白了。在这里,大家可以清清楚楚地看到,所谓的控件,完完全全地是个类。所谓的类,其实就是具有一定功能,可以进行某类操作的程序块,这个程序块可以有变量、属性、可以有函数、代码,当然也可以有窗体、界面。

    2、为了演示方便,我们没有从数据库中读取数据,而是做了一个函数,动态创建一个具有Ilist接口的简单的表格数据。

    3DataList的模板和Repeater差不多,还是手工做,方便一些。和Repeater相比,主要多了一个RepeatColumns属性,在电子商务系统中,用来展示商品列表比较方便,但默认没有分页功能,可以通过本例,自定义实现。

    二、呈现

    【效果】

    【操作步骤】

    1CustomDataList.cs中改写基类的Render()函数来实现,完整代码如下:

    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}>< 上一页</a>";
            private const string LINK_MORE = "<a href=?page={0}>下一页 ></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、在浏览器中查看运行结果如效果图示。

      【说明】

    1、这段代码的主要功能是呈现一个二行二列的表格,为了显示得清晰一些,设置了这个表格的边框为1,从效果图可以看出,原来DataList显示的内容,显示在表格的第一行,合并单元格后的单元格中,第二行的两个单元格,分别显示“<上一页”和“下一页>”。

    2、这两个单元格内的文字,分别加了个链接参数?page={0},page的值暂时由默认的当前页号加1或减1获得。

    3、使用类Regex是根据正则表达式“&page=\d+”获取并替代网址中的参数page,具体用法可参阅MSDN的相关内容。

    4if (!DesignMode)是判断当前是否在设计时状态,以决定{}中的语句是否执行。因为{}中的语句需要从地址中获取参数page后面的字符串query,这个query在设计时是未知数,会影响到控件内容的呈现,所以,在设计时不执行,而并不影响实际使用。

    三、分页显示

    【效果】

     

    【操作步骤】

    1CustomDataList.cs中为自定义控件添加属性,并改写,完整代码如下:

    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}>< 上一页</a>";
            private const string LINK_MORE = "<a href=?page={0}>下一页 ></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中设置CustomDataList1的属性PageSize="4" EmptyText="No Data found.",这两个属性可以属性窗口中设置,如图示:

    3、在浏览器中查看运行结果如效果图示。

     

    【说明】

    1CustomDataList分页的主要逻辑是,改写DataListDataSource属性,在设置数据源CustomDataList1.DataSource =CreateDataSource();时,用Ilist类指针dataSource (也就是俗称的接口)接收过来,同时,获取数据源中数据项的个数ItemCount,然后,改写DataListDataBind()函数,在函数中通过当前页号CurrentPageIndex(当前页号初始值为0,在后面,点击“上一页”“下一页”时需要重新设置)与属性中设置的每页的数据项个数pageSize获取起始数据项int start = CurrentPageIndex * pageSize;。因为最后一页数据项的个数不一定,所以该页的个数需要重新确定一下int size =Math.Min(pageSize,ItemCount - start);,有了这两个值,就可以把相应的数据项取出存放在重新定义的IList pageList =newArrayList();中,最后,把这个pageList做为DataList的数据源与DataList绑定。

    2、在属性窗口中设置属性,需要刷新一下,在工作区窗口中把Default.aspx关闭,再重新打开就可以了。

    四、添加事件

    【效果】

     

    【操作步骤】

     

    1、在CustomDataList.cs中,添加事件PageIndexChanged

    public event DataGridPageChangedEventHandler PageIndexChanged;
    
    virtual protected void OnPageIndexChanged(DataGridPageChangedEventArgs e)
    {
        if (PageIndexChanged != null)
            PageIndexChanged(this, e);
    }
    

    2、在Default.aspx中设置事件处理函数onpageindexchanged="CustomDataList1_PageIndexChanged",这个设置也可以在属性窗口中的事件选项卡中进行,如图示:

    3、在Default.aspx.cs中添加代码,并删除原来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)
        {
        }
    
        //创建符合IList接口的表格示例数据
        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、在浏览器中查看运行结果如效果图示。

    【说明】

    1DataGridPageChangedEventHandler是委托,原型为:

    publicdelegatevoidDataGridPageChangedEventHandler(Object source,DataGridPageChangedEventArgs e)

     

    C#中的委托,类似于CC++中的函数指针,从DataGridPageChangedEventHandler的原型可以看出,它相当于是形参为(Object source,DataGridPageChangedEventArgs e),返回值为void的函数指针。只不过在C#中,委托被做成了类,是一种数据类型,需要实例化成类变量,才能存放函数的指针变量。

    2、在属性窗口的事件选项卡中设置事件处理程序,需要刷新一下,在工作区窗口中把Default.aspx关闭,再重新打开就可以了。

    3、运行结果没有数据显示,是因为事件PageIndexChanged的事件处理程序没有被触发。

     

    五、触发事件处理程序

    【效果】

     

    【操作步骤】

    1CustomDataList.cs中改写DataListOnLoad()函数,并添加函数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、在浏览器中查看运行结果如效果图示。

    【说明】

    1、触发(Raise)事件有很多方式,在这里,重载并修改了DataListOnLaod()函数,在装载自定义控件CustomDataList时,读取地址中的参数page,并根据page的值获取要显示的页号index (如果page为空的话,就设为0),并把index交给函数SetPage(),在SetPage()中调用OnPageIndexChanged(),进而通过PageIndexChanged(this, e);触发了事件处理函数。因为,事件相当于CC++中的函数指针变量,它的值,在Default.aspx中设置CustomDataList的事件处理函数时,就已经指向了形参为(objectsource,DataGridPageChangedEventArgs e),返回值为void类型的函数了。

    2、委托我们使用的是现成的不需要声明的DataGridPageChangedEventHandler,委托要传递的参数变量也是现成的不需要声明的DataGridPageChangedEventArgs,通过newDataGridPageChangedEventArgs(null, index),就可以直接给参数变量赋值并传递了。

    3、前面,为了强调显示效果,我们把“<上一页”“下一页>”无条件地显示了,事实上,如果页号为0,就不应该显示当前页“<上一页”,而页号为最后一页的时候,如果显示“下一页>”,由于链接问题,点击会出现错误的。为此,需要在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));
    

      


     源代码:http://download.csdn.net/detail/yousuosi/4669295

    版权所有©2012,WestGarden.欢迎转载,转载请注明出处.更多文章请参阅博客http://WestGarden.cnblogs.com/

     

  • 相关阅读:
    tcp/ip基础
    Fiddler进行模拟Post提交json数据,总为null解决方式(转)
    mysql function动态执行不同sql语句
    SQL语句中各个部分的执行顺序(转)
    shell的初步介绍
    linux分区
    转00600异常解决方案:ORA-00600: 内部错误代码, 参数: [19004], [], [], [], [], []
    一小时执行一次存储过程
    Oracle中的job的定时任务
    Oracle 存储过程错误之PLS-00201: 必须声明标识符
  • 原文地址:https://www.cnblogs.com/WestGarden/p/2732866.html
Copyright © 2011-2022 走看看