2017年7月25日 星期二

GridView 自訂分頁

一般 GridView 可以交給自動分頁產生出分頁效果,只需要將 GridView 的屬性 AllowPaging 設為 true,再搭配取得資料的語法,即可完成。
GridView 會依據資料筆數 和 GridView.PageCount 自動計算出頁數。
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        GridView1.DataSource = GetData();
        GridView1.DataBind();
    }
}

private DataTable GetData()
{
    // 讀取資料
}

// 翻頁時改變 PageIndex 後重新綁定 GridView 的資料
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
    GridView gridview = (GridView)sender;
    GridView.PageIndex = e.NewPageIndex;
    GridView.DataSource = GetData();
    GridView.DataBind();
}
因為GridView其實是將全部的資料都載入後,只顯示某一頁的資訊出來,所以當讀取的資料太多時就會造成載入的間很久。


此時可以使用自訂分頁的方式,自訂分頁除了要將 GridView 的屬性 AllowPaging 設為 true 之外,還要將 GridView 的屬性 AllowCustomPaging 設為 true,然後再在程式碼中指定 GridView.VirtualItemCount (虛擬 GridView 總共有幾筆資料),然後 GridView 會依據 VirtualItemCount 和 GridView.PageCount 自動計算出頁數,具體做法大致如下:
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        // GridView.VirtualItemCount:虛擬 GridView 總共有幾筆資料
        GridView1.VirtualItemCount = GetAllDataCount();
        GridView1.DataSource = GetSpecPageData(0);
        GridView1.DataBind();
    }
}
private int GetAllDataCount()
{
    // 讀取全部資料的筆數
}

/// 只讀取指定頁的資料
private DataTable GetSpecPageData(int PageIndex)
{
    // 比方每頁要顯示 15 筆
    // 讀取第一頁要顯示的資料,那就只讀取 TOP 15
    // 或是若要讀取第三頁 31 到第 45 筆,則可以用 OFFSET 30 ROWS FETCH NEXT 15 ROWS ONLY
    // 意思是是位移 30 筆之後,再往下取 15 筆資料
   請參考MIS2000 Lab
}

翻頁時改變 PageIndex 後重新綁定 GridView 的資料
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
    GridView gridview = (GridView)sender;
    GridView.PageIndex = e.NewPageIndex;
    GridView.DataSource = GetSpecPageData(e.NewPageIndex);
    GridView.DataBind();
}
此時遇到的題目是 GridView 的每頁筆數不一致(比方某個欄位要固定只顯示幾種資料),所以除了上述的寫法之外,還要加上一點點修正,如下:

加上一個全域變數,用以儲存每頁的筆數資訊
Dictionary<int, int> dictCountPerPage;
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        dictPerPageCount = GetPerPageCount();
        GridView1.PageCount = dictPerPageCount[0];  // 指定第一頁的筆數
        // GridView.VirtualItemCount:計算虛擬 GridView 總共有幾筆資料(因為每頁筆數不一,所以以要顯示的該頁的筆數當基準,用以計算出虛擬總筆數,好產生頁數(碼)         GridView1.VirtualItemCount = GridView1.PageCount * dictPerPageCount.Count;         GridView1.DataSource = GetSpecPageData(0);         GridView1.DataBind();     } } /// 依需求記錄每頁要顯示的資料筆數 /// Key: 頁碼, Value: 每頁到第幾筆資料 private Dictionary<int, int> GetPerPageCount() {     // 讀取全部每頁的資料的筆數     // 例如:     // Dictionary<int, int> dict = new Dictionary<int, int>();     // dict.Add(0, 10); // 第 1 頁: 0~10 筆     // dict.Add(1, 16); // 第 2 頁: 11~16 筆    // dict.Add(2, 18); // 第 3 頁: 17~18 筆     // dict.Add(3, 22); // 第 4 頁: 19~22 筆     // Session.Add("PerPageCount", dictPerPageCount); 將分頁資訊記錄在 Session     // return dict; }
/// 只讀取指定頁的資料 private DataTable GetSpecPageData(int PageIndex) {     // 比方每頁要顯示 15 筆     // 讀取第一頁要顯示的資料,那就只讀取 TOP 15     // 或是若要讀取第三頁 31 到第 45 筆,則可以用 OFFSET 30 ROWS FETCH NEXT 15 ROWS ONLY     // 意思是是位移 30 筆之後,再往下取 15 筆資料     請參考MIS2000 Lab     // SQL 語法:    StringBuilder SQL = new StringBuilder("...");     SQL.Append(" ORDER BY 1, 2, 3, 4");     // 取回第幾筆~第幾筆資料     if (CurrentPage == 0)         SQL.AppendFormat(" OFFSET {0} ROWS FETCH NEXT {1} ROWS ONLY", 0, dicRowCountPerPage[CurrentPage]);     else         SQL.AppendFormat(" OFFSET {0} ROWS FETCH NEXT {1} ROWS ONLY", dictCountPerPage[PageIndex- 1], dictCountPerPage[PageIndex] - dictCountPerPage[PageIndex- 1]);     // 每次都重新指定 PageCount 和 VirtualItemCount     if (PageIndex== 0)         GridView1.PageSize = dictCountPerPage[PageIndex];     else         GridView1.PageSize = dictCountPerPage[PageIndex] - dictCountPerPage[PageIndex - 1];     GridView1.VirtualItemCount = GridView1.PageSize * dictCountPerPage.Count; } /// 翻頁時改變 PageIndex 後重新綁定 GridView 的資料 protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e) {     GridView gridview = (GridView)sender;     GridView.PageIndex = e.NewPageIndex;     if (dictCountPerPage == null)         dictCountPerPage = (Dictionary<int, int>)Session["PerPageCount"];     GridView.DataSource = GetSpecPageData(e.NewPageIndex);     GridView.DataBind(); }