2013年9月4日 星期三

[轉貼] 製作可重複使用的分頁WebUserControl


這次要把分頁區塊包在WebUserControl,讓之後其他的 *.aspx有ListView或GridView的畫面,只要一拉進WebUserControl,就可以馬上做分頁

對著專案新增項目

接著就是做搬移程式碼的動作
pageListViewOrGridView.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="pageListViewOrGridView.ascx.cs"
    Inherits="pageListViewOrGridView" %>
<style type="text/css">
    /*分頁區塊的CSS*/
    .rsmenu
    {
        color: #4c4c4c;
        padding: 15px 0;
        clear: both;
        text-align: center;
    }
    .rsmenu span, .rsmenu span a
    {
        color: #808e02;
    }
    .pgbtn
    {
        background: #808E02;
        border: none medium;
        color: #fff;
        cursor: pointer;
        width: 40px;
        height: 19px;
    }
    .pgbtn:hover
    {
        background: #99a535;
    }
</style>
<%--分頁區塊--%>
<div class="rsmenu">
    合計<asp:Literal ID="li_totalRows" runat="server" />
    <span>|
        <asp:LinkButton Text="最前頁" ID="lnkFirstPage" runat="server" OnClick="lnkFirstPage_Click" />
        |
        <asp:LinkButton Text="上一頁" ID="lnkPrePage" runat="server" OnClick="lnkPrePage_Click" />|
    </span>選擇頁數   <b>第<asp:DropDownList runat="server" ID="dl_currentPage">
    </asp:DropDownList>
        頁</b> <span>|
            <asp:LinkButton Text="下一頁" ID="lnkNextPage" runat="server" OnClick="lnkNextPage_Click" />|
            <asp:LinkButton Text="最後頁" runat="server" ID="lnkLastPage" OnClick="lnkLastPage_Click" />|
        </span>每頁
    <asp:DropDownList runat="server" ID="dl_pageSize">
        <asp:ListItem Value="5" Text="5" />
        <asp:ListItem Value="10" Text="10" />
    </asp:DropDownList>
    筆
    <asp:Button ID="btnToPage" runat="server" CssClass="pgbtn" Text="跳頁" OnClick="btnToPage_Click" />
</div>



.ascx的Code-Behind(未完整)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
/*要引用以下三個命名空間*/
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;

public partial class pageListViewOrGridView : System.Web.UI.UserControl
{
    //連線字串
    string connStr = WebConfigurationManager.ConnectionStrings["connStr"].ConnectionString;
    protected void Page_Load(object sender, EventArgs e)
    {

    }


    #region 分頁資料,總筆數、總頁數文字顯示處理
    protected void showData(int currentPage, int pageSize, string sql)
    {

        DataSet ds = this.Query(sql);//查詢出此次的資料


        #region 總頁數、總筆數文字顯示處理

        int totalRows = ds.Tables[0].Rows.Count;//總筆數
        li_totalRows.Text = totalRows.ToString();

        //總頁數(自己算)
        int totalPages = (totalRows / pageSize);//取商數(總筆數除以每頁顯示幾筆,得到總頁數)
        if (totalRows % pageSize > 0)//若餘數大於0,不整除的話,總頁數要加1,道理如同小學數學題 多出來的學生也要多叫一部遊覽車送去郊遊是一樣的
        {
            totalPages++;
        }
        //int totalPages = pds.PageCount;

        //防呆寫法
        if (currentPage > totalPages)
            currentPage = totalPages;
        if (currentPage < 1)
            currentPage = 1;


        //ListView顯示分頁後的資料,並做DataBind(),這次的currentPage經過防呆後,應該是正確的值
        /*lv_showData還沒有傳進來,先註解*/
        /*System.Web.UI.WebControls.PagedDataSource pds =
                                                  DBUtility.pageData(ds, pageSize, currentPage, lv_showData);

        */




        dl_currentPage.Items.Clear();
        for (int i = 1; i <= totalPages; i++)
        {
            dl_currentPage.Items.Add(i.ToString());
        }
        //目前第幾頁的下拉選單選擇值
        dl_currentPage.SelectedValue = currentPage.ToString();
        //每頁顯示幾筆的下拉選單選擇值
        dl_pageSize.SelectedValue = pageSize.ToString();

        //第一頁和最後一頁時,第一頁、上一頁、下一頁、最末頁按鈕Enabled的處理防呆
        if (currentPage == 1)//目前在第一頁
        {
            lnkFirstPage.Enabled = false;
            lnkPrePage.Enabled = false;
        }
        else
        {
            lnkFirstPage.Enabled = true;
            lnkPrePage.Enabled = true;
        }
        if (currentPage == totalPages)//目前在最後一頁
        {
            lnkLastPage.Enabled = false;
            lnkNextPage.Enabled = false;
        }
        else
        {
            lnkLastPage.Enabled = true;
            lnkNextPage.Enabled = true;
        }

        #endregion










    }
    #endregion

    /// <summary>
    /// 傳入SQL查詢語句,回傳DataSet
    /// </summary>
    /// <param name="sql"></param>
    /// <returns></returns>
    private DataSet Query(string sql)
    {
        DataSet ds = new DataSet();
        using (SqlConnection conn = new SqlConnection(this.connStr))
        {
            SqlDataAdapter da = new SqlDataAdapter(sql, conn);
            da.Fill(ds);
        }
        return ds;


    }






    //第一頁Click
    protected void lnkFirstPage_Click(object sender, EventArgs e)
    {
        dl_currentPage.SelectedValue = "1";//到第一頁
        this.btnToPage_Click(null, null);//跳頁事件
    }

    //上一頁Click
    protected void lnkPrePage_Click(object sender, EventArgs e)
    {
        dl_currentPage.SelectedValue = Convert.ToInt32(dl_currentPage.SelectedValue) - 1 + "";
        this.btnToPage_Click(null, null);//跳頁事件
    }
    //下一頁Click
    protected void lnkNextPage_Click(object sender, EventArgs e)
    {
        dl_currentPage.SelectedValue = Convert.ToInt32(dl_currentPage.SelectedValue) + 1 + "";
        this.btnToPage_Click(null, null);//跳頁事件
    }

    //最後一頁
    protected void lnkLastPage_Click(object sender, EventArgs e)
    {
        dl_currentPage.SelectedValue = dl_currentPage.Items[dl_currentPage.Items.Count - 1].Value;
        this.btnToPage_Click(null, null);//跳頁事件
    }

    #region 跳頁事件postback的處理
    protected void btnToPage_Click(object sender, EventArgs e)
    {
        #region 防呆,當查詢無資料時,dl_currentPage.SelectedValue會空字串,為了避免再按一次搜尋或再次postback時,程式掛掉,加入以下判斷
        int currentPage = 1;
        if (dl_currentPage.SelectedValue == "")
        {
            currentPage = 1;
        }
        else
        {
            currentPage = Convert.ToInt32(dl_currentPage.SelectedValue);
        }

        /*每次跳頁postback就要經過queryData方法,SQL語句要經過篩選*/
        /*先註解*/
        //this.queryData(currentPage, Convert.ToInt32(dl_pageSize.SelectedValue));
        #endregion
    }
    #endregion
}
要先註解的地方:
/*這時候ListView還沒傳進來*/
        /*System.Web.UI.WebControls.PagedDataSource pds =
                                                  DBUtility.pageData(ds, pageSize, currentPage, lv_showData);
*/

#region 跳頁事件postback的處理
    protected void btnToPage_Click(object sender, EventArgs e)
    {
        #region 防呆,當查詢無資料時,dl_currentPage.SelectedValue會空字串,為了避免再按一次搜尋或再次postback時,程式掛掉,加入以下判斷
        int currentPage = 1;
        if (dl_currentPage.SelectedValue == "")
        {
            currentPage = 1;
        }
        else
        {
            currentPage = Convert.ToInt32(dl_currentPage.SelectedValue);
        }

        /*每次跳頁postback就要經過queryData方法*/
        /*queryData方法為經過查詢條件篩選過的SQL語句,因為每個畫面的查詢條件不一樣
         * 故queryData方法內的篩選條件也不一樣,不用把queryData方法也搬移到WebUserControl*/
        //this.queryData(currentPage, Convert.ToInt32(dl_pageSize.SelectedValue));
        #endregion
    }
    #endregion


為了讓此WebUserControl能夠接到從 *.aspx傳過來的值
所以要再改寫一下,大概要傳進來的值有ListView控制項、sql語句,這兩個要從Session中提取
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
/*要引用以下三個命名空間*/
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;

//要傳給此WebUserControl的值
//Session["sql"]和Session["DataBoundControl"]
public partial class pageListViewOrGridView : System.Web.UI.UserControl
{
    /*連線字串*/
    string connStr = WebConfigurationManager.ConnectionStrings["connStr"].ConnectionString;
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)//Get Method要做的事
        {
            int currentPage = 1;//預設目前第一頁
            int pageSize = 5;//預設每頁顯示5筆
            if (Session["sql"]!=null)
            {
                string sql = (string)Session["sql"];
                this.showData(currentPage, pageSize, sql);
            }

        }
    }


    #region 分頁資料,總筆數、總頁數文字顯示處理
    protected  void showData(int currentPage, int pageSize, string sql)
    {

        DataSet ds = this.Query(sql);//查詢出此次的資料


        #region 總頁數、總筆數文字顯示處理

        int totalRows = ds.Tables[0].Rows.Count;//總筆數
        li_totalRows.Text = totalRows.ToString();

        //總頁數(自己算)
        int totalPages = (totalRows / pageSize);//取商數(總筆數除以每頁顯示幾筆,得到總頁數)
        if (totalRows % pageSize > 0)//若餘數大於0,不整除的話,總頁數要加1,道理如同小學數學題 多出來的學生也要多叫一部遊覽車送去郊遊是一樣的
        {
            totalPages++;
        }

        //int totalPages = pds.PageCount;

        //防呆寫法
        if (currentPage > totalPages)
            currentPage = totalPages;
        if (currentPage < 1)
            currentPage = 1;


        //從Session取得ListView控制項
        DataBoundControl dbc = this.getDataBoundControlFromSession();
        //ListView顯示分頁後的資料,並做DataBind(),currentPage經過防呆後,應該是正確的值
        System.Web.UI.WebControls.PagedDataSource pds =
                                                  DBUtility.pageData(ds, pageSize, currentPage, dbc);

        




        dl_currentPage.Items.Clear();
        for (int i = 1; i <= totalPages; i++)
        {
            dl_currentPage.Items.Add(i.ToString());
        }
        //目前第幾頁的下拉選單選擇值
        dl_currentPage.SelectedValue = currentPage.ToString();
        //每頁顯示幾筆的下拉選單選擇值
        dl_pageSize.SelectedValue = pageSize.ToString();

        //第一頁和最後一頁時,第一頁、上一頁、下一頁、最末頁按鈕Enabled的處理防呆
        if (currentPage == 1)//目前在第一頁
        {
            lnkFirstPage.Enabled = false;
            lnkPrePage.Enabled = false;
        }
        else
        {
            lnkFirstPage.Enabled = true;
            lnkPrePage.Enabled = true;
        }
        if (currentPage == totalPages)//目前在最後一頁
        {
            lnkLastPage.Enabled = false;
            lnkNextPage.Enabled = false;
        }
        else
        {
            lnkLastPage.Enabled = true;
            lnkNextPage.Enabled = true;
        }

        #endregion










    }
    #endregion

    /// <summary>
    /// 傳入SQL查詢語句,回傳DataSet
    /// </summary>
    /// <param name="sql"></param>
    /// <returns></returns>
    private DataSet Query(string sql)
    {
        DataSet ds = new DataSet();
        using (SqlConnection conn = new SqlConnection(this.connStr))
        {
            SqlDataAdapter da = new SqlDataAdapter(sql, conn);
            da.Fill(ds);
        }
        return ds;


    }

    /// <summary>
    /// 從Session中抓出ListView或GridView
    /// </summary>
    /// <returns></returns>
    private DataBoundControl getDataBoundControlFromSession()
    {
        DataBoundControl dbc = null;
        if (Session["DataBoundControl"] is ListView)
        {
            dbc = (ListView)Session["DataBoundControl"];

        }
        else if (Session["DataBoundControl"] is GridView)
        {
            dbc = (GridView)Session["DataBoundControl"];
        }

        return dbc;
    }




    //第一頁Click
    protected void lnkFirstPage_Click(object sender, EventArgs e)
    {
        dl_currentPage.SelectedValue = "1";//到第一頁
        this.btnToPage_Click(null, null);//跳頁事件
    }

    //上一頁Click
    protected void lnkPrePage_Click(object sender, EventArgs e)
    {
        dl_currentPage.SelectedValue = Convert.ToInt32(dl_currentPage.SelectedValue) - 1 + "";
        this.btnToPage_Click(null, null);//跳頁事件
    }
    //下一頁Click
    protected void lnkNextPage_Click(object sender, EventArgs e)
    {
        dl_currentPage.SelectedValue = Convert.ToInt32(dl_currentPage.SelectedValue) + 1 + "";
        this.btnToPage_Click(null, null);//跳頁事件
    }

    //最後一頁
    protected void lnkLastPage_Click(object sender, EventArgs e)
    {
        dl_currentPage.SelectedValue = dl_currentPage.Items[dl_currentPage.Items.Count - 1].Value;
        this.btnToPage_Click(null, null);//跳頁事件
    }

    #region 跳頁事件postback的處理
    /*要改成public,因為其他.aspx畫面經過自己的queryData方法後,要呼叫此btnToPage_Click方法*/
    public void btnToPage_Click(object sender, EventArgs e)
    {
        #region 防呆,當查詢無資料時,dl_currentPage.SelectedValue會空字串,為了避免再按一次搜尋或再次postback時,程式掛掉,加入以下判斷
        //先抓出此WebUserControl上的currentPage和pageSize
        int currentPage = 1;
        if (dl_currentPage.SelectedValue == "")
        {
            currentPage = 1;
        }
        else
        {
            currentPage = Convert.ToInt32(dl_currentPage.SelectedValue);
        }
        int pageSize = Convert.ToInt32(dl_pageSize.SelectedValue);
         
        /*queryData方法為經過查詢條件篩選過的SQL語句,因為每個畫面的查詢條件不一樣
         * 故queryData方法內的篩選條件也不一樣,不用把queryData方法也搬移到此WebUserControl*/

        /*這時候的Session["sql"]可能是篩選過的SQL語句*/
        if (Session["sql"] != null)
        {
            string sql = (string)Session["sql"];
            this.showData(currentPage, pageSize, sql);
        }
        #endregion
    }
    #endregion
}

接著回到.aspx,把畫面上的東西也稍作整理
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="PagedDataSourceDemo.aspx.cs"
    Inherits="PagedDataSourceDemo" %>

<%@ Register TagPrefix="include" TagName="pageData" Src="~/pageListViewOrGridView.ascx" %>

<!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></title>
</head>
<body>
    <form id="form1" runat="server">
    
     
    <%--查詢條件的下拉選單,OnSelectedIndexChanged事件要改--%>
    <asp:DropDownList runat="server" ID="ddl_SelectID" AutoPostBack="true"  OnSelectedIndexChanged="queryData">
        <asp:ListItem Text="請選擇" Value="-1" />
        <asp:ListItem Text="5" Value="5" />
        <asp:ListItem Text="10" Value="10" />
    </asp:DropDownList>
    <%--表格式ListView--%>
    <asp:ListView ID="lv_showData" runat="server">
        <ItemTemplate>
            <tr>
                <td>
                    <asp:Literal ID="idLiteral" runat="server" Text='<%# Eval("id") %>'  />
                </td>
                <td>
                    <asp:Literal ID="titleLiteral" runat="server" Text='<%# Eval("title") %>' />
                </td>
            </tr>
        </ItemTemplate>
        <LayoutTemplate>
            <table id="itemPlaceholderContainer" runat="server" align="center" cellpadding="0"
                cellspacing="0" border="1" style="border-style: solid;">
                <tr>
                    <th runat="server">
                        id
                    </th>
                    <th runat="server">
                        title
                    </th>
                </tr>
                <tr id="itemPlaceholder" runat="server">
                </tr>
            </table>
        </LayoutTemplate>
    </asp:ListView>
    
    <%--分頁區塊--%>
    <include:pageData ID="pageData1" runat="server" />
    </form>
</body>
</html>



.aspx的Code-Behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;

public partial class PagedDataSourceDemo : System.Web.UI.Page
{

    string sqlSelect = " Select * from tb_data Where 1=1 ";
    string sqlOrderBy = " Order by id ASC";
    protected void Page_Load(object sender, EventArgs e)
    {
        //不管是不是postback,都要把ListView控制項存在Session裡
        Session["DataBoundControl"] = this.lv_showData;
        if (!IsPostBack)//Get Method要做的動作
        {
            //撈全部的資料
            Session["sql"] = this.sqlSelect + this.sqlOrderBy;
            //.aspx的Page_Load事件執行完後才會去執行.ascx的Page_Load事件
            //之後的資料呈現就交給 分頁WebUserControl的Page_Load事件處理
        }
    }

    //下拉選單更動或假設按了搜尋按鈕都要經過此SQL語法
    protected void queryData(object sender,EventArgs e)
    {
        string sql = this.sqlSelect;

        if (ddl_SelectID.SelectedIndex>0)//有選擇
        {
            sql += " And id > '"+ddl_SelectID.SelectedValue+"'";
        }

        //排序
        sql += this.sqlOrderBy;

        //篩選過的SQL語句儲存在Session,讓.ascx可以讀得到
        Session["sql"] = sql;

        //呼叫跳頁方法
        ((pageListViewOrGridView)this.FindControl("pageData1")).btnToPage_Click(null, null);
    }



   
  
}

執行結果和上一個範例是一樣的::[ASP.net WebForm] 使用PagedDataSource物件實現手寫分頁 (適合初學者)
所以現在有任何的 *.aspx要套用此分頁WebUserControl的話
記得追加修改以下粗體字部份
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="PagedDataSourceDemo.aspx.cs"
    Inherits="PagedDataSourceDemo" %>

<%@ Register TagPrefix="include" TagName="pageData" Src="~/pageListViewOrGridView.ascx" %>

<!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></title>
</head>
<body>
    <form id="form1" runat="server">
    
     
    <%--查詢條件的下拉選單,OnSelectedIndexChanged事件要改--%>
    <asp:DropDownList runat="server" ID="ddl_SelectID" AutoPostBack="true"  OnSelectedIndexChanged="queryData">
        <asp:ListItem Text="請選擇" Value="-1" />
        <asp:ListItem Text="5" Value="5" />
        <asp:ListItem Text="10" Value="10" />
    </asp:DropDownList>
    <%--表格式ListView--%>
    <asp:ListView ID="lv_showData" runat="server">
        <ItemTemplate>
            <tr>
                <td>
                    <asp:Literal ID="idLiteral" runat="server" Text='<%# Eval("id") %>'  />
                </td>
                <td>
                    <asp:Literal ID="titleLiteral" runat="server" Text='<%# Eval("title") %>' />
                </td>
            </tr>
        </ItemTemplate>
        <LayoutTemplate>
            <table id="itemPlaceholderContainer" runat="server" align="center" cellpadding="0"
                cellspacing="0" border="1" style="border-style: solid;">
                <tr>
                    <th runat="server">
                        id
                    </th>
                    <th runat="server">
                        title
                    </th>
                </tr>
                <tr id="itemPlaceholder" runat="server">
                </tr>
            </table>
        </LayoutTemplate>
    </asp:ListView>
    
    <%--分頁區塊--%>
    <include:pageData ID="pageData1" runat="server" />
    </form>
</body>
</html>


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;

public partial class PagedDataSourceDemo : System.Web.UI.Page
{

    string sqlSelect = " Select * from tb_data Where 1=1 ";
    string sqlOrderBy = " Order by id ASC";
    protected void Page_Load(object sender, EventArgs e)
    {
        //不管是不是postback,都要把ListView控制項存在Session裡
        Session["DataBoundControl"] = this.lv_showData;
        if (!IsPostBack)//Get Method要做的動作
        {
            //撈全部的資料
            Session["sql"] = this.sqlSelect + this.sqlOrderBy;
            //.aspx的Page_Load事件執行完後才會去執行.ascx的Page_Load事件
            //之後的資料呈現就交給 分頁WebUserControl的Page_Load事件處理
        }
    }

    //下拉選單更動或假設按了搜尋按鈕都要經過此SQL語法
    protected void queryData(object sender, EventArgs e)
    {
        string sql = this.sqlSelect;

        if (ddl_SelectID.SelectedIndex > 0)//有選擇
        {
            sql += " And id > '" + ddl_SelectID.SelectedValue + "'";
        }

        //排序
        sql += this.sqlOrderBy;

        //篩選過的SQL語句儲存在Session,讓.ascx可以讀得到
        Session["sql"] = sql;

        //呼叫跳頁方法
        ((pageListViewOrGridView)this.FindControl("pageData1")).btnToPage_Click(null, null);
    }





}


衍伸閱讀其他部落客文章:

沒有留言:

張貼留言