2008年8月20日

Gridview 自訂分頁

拖稿拖了好幾天 坎尼夢見了富檻出新連載
所以上來把欠的東西還一還 (富檻快給我畫

坎尼廢話就少講一點 直接進入 自訂分頁 Sample

首先,畫面上要有個 Gridview
這邊坎尼偷懶用了 SqlDataSource 見下圖

可以看到 Pager 已經出現了 來看一下原始碼 如下圖

要自訂分頁第一個要件就是 Gridview allow paging 設為 true
再來就是Gridview 上按右鍵EditTemplate -> PagerTemplate
就會進入到編輯畫面 再把要加入的 Controls 拖進去

如果嫌 Design 模式很難用 想用原始碼去編輯
就直接在 Gridview 的 PageTemplate 把 Controls 給拖進去
沒看到 PageTemplate 怎麼辦? 自己打啊 XDD

再來解說一下坎尼這個自訂分頁
控制項分別為 Label LinkButton*4 DropDownList Label
LinkButton皆有設定 CommandArgumentOnClick事件
DropDownList 也有 SelectedIndexChanged 事件
這些稍後會提到 先來看一下實際畫面

以下就來解說分頁事件是如何進行
首先是 DropDownList 的 SelectedIndexChanged 事件
很簡單 只要SelectedIndex 設定給 GridviewPageIndex 即可

這邊要注意的地方有兩個
要取得 Pager 裡的 DropDownList 記得是用 Gridview.BottomPagerRow
(當然 如果 PagerRow 設定為在表格上方 就是用 Gridview.TopPagerRow)

再來就是被註解起來的 GetData() 函式
因為坎尼這範例是用 SqlDataSource 當資料來源的方式
所以並不需要特別去做資料繫結的動作 只要 PostBack 即可
但如果是要自行取得 DataSource 來繫結
這邊的 GetData() 就是取代各位的 取得 DataSource 的函式


接下來是 LinkButton 的 Click 事件
先是取得目前按下的 LinkButton 是哪個鍵
分別有 第一頁 上一頁 下一頁 及 最後一頁

會依點下的按鍵不同 計算該到哪一頁
index 設給 Gridview.PageIndex
同樣的 這邊的 GetData() 函式作用如上面解說

接下來就是這個自訂分頁的精華部分
先是在 Gridview 的 DataBound 事件加入 pageSet() 函式
這函式需要傳入要分頁的 Gridview

當然 若是通通寫在同一個 class 就可以省了把 Gridview 傳入
可是 為了增加程式彈性及提高重複使用率 建議是多寫一道手續
(比方講 把這個函式包在另一個 class 或是 寫成User Control)

下圖就是最麻煩 坎尼已經想睡了不太想講的部分

好啦 還是解說一下 (大家可以點圖放大 看一下程式在幹嘛)
首先 把傳入的 object 轉為 Gridview
再將 Gridview 的 PagerRow裡的 Controls 取出做處理
顯示全部筆數 目前先給 pageCount * pageSize (當然 這邊是不準的 要再做其他處理)
顯示全部頁數 給 pageCount

接下來 取得跳頁用的 DropDownList 並重新給予 Item
「這樣不會每次 DataBound 就重覆的把 item 給加進去嗎?」
不會的 因為這邊是動態產生
所以只要 PostBack 下拉選單的 Items 就會被清空
因此才要再重新把項目給加回去

再來的就是判斷 LinkButton 是否作用
最後再把下拉選單設定為目前的頁數

其實這個函數最外層還要加個判斷 if(gv.PageCount > 1)
因為 GridView 預設 如果無分頁(頁數小於1) 則不顯示 PagerRow
這段程式碼就會因此出現 Exception

下面就是實際操作畫面



這篇真是又臭又長 希望有人有耐心看到這邊 XD
最後再提一個東西 DataPager
這是 .net framework 3.5 新增的控制項
目的也是在做分頁的顯示及控制
可惜目前只支援 ListView 控制項

若是想在 Gridview 上要自己做美美的分頁
還是只能靠自己寫分頁樣板及事件

20 則留言:

匿名 提到...

HI~坎尼
我想請問 如果想讓上下方同時都有分頁的效果 是要設定 Gridview.PagerSettings.Position = PagerPosition.TopAndBottom;

那上方的下拉選單跳頁SelectedIndexChanged 該如何指定

因為上方的DropDownList 是要取TopPagerRow的FindControl 就無法共用同一個SelectedIndexChanged

而我目前測試的結果Grid 似乎不能有兩個PagerTemplate來區分上下的下拉選單

麻煩坎尼解答一下~3q

匿名 提到...

坎尼大大
請問您的兩個分頁 要如何結合?
http://dotnetmis91.blogspot.com/2008/08/gridview.html

不知道可不可行

謝謝

坎尼 提到...

若要把這兩個分頁結合,請利用本篇的自訂分頁技巧,自己加入 數字 的選單
建議是自己加入 10 個 LinkButton ,再用目前的頁碼去計算該顯示的數字
(比方講,1 2 3...10)

跳頁的事件可直接套用本文的事件處理 (見下圖)
http://1.bp.blogspot.com/_bGOQZqQ9oEM/SKucE_qMGXI/AAAAAAAAAJs/NuymfnAOd60/s1600-h/udPager4.png

另外回一下一樓
(雖然是很久之前的回應,我沒收到訊息通知,抱歉啦)
若是上下兩層的 PagerRow 都打開,記得把事件裡的 FindControl 也寫兩份
一個是用 Gridview.TopPagerRow
另一個是 Gridview.BottomPagerRow

匿名 提到...

請問坎尼大大,加入 10 個 LinkButton ,再用目前的頁碼去計算該顯示的數字 這樣是要怎麼做 什麼意思阿? 那頁數的數字是要怎麼改變?

看樣子2樓的大大是會了,沒有提出其他問題..

坎尼 提到...

他應該只是時間過太久所以忘了吧 (汗)

頁數就是靠目前的 Gridview.PageIndex 去算出該顯示的頁碼

舉例來講,全部的資料有 28 頁,目前的頁碼在 12 頁
就用 for 迴圈把 LinkButton.Text 改成 11 12...20

若是目前頁碼跳到 23 頁
一樣用 for 迴圈把 LinkButton.Text 改成 21 22...28
最後兩個 LinkButton 就把 Visible 設定成 false

下次有空我再來做個集大成的 Gridview Pager 好了...

匿名 提到...

哈哈...(汗)

嗯嗯,大致瞭解了,感謝您。

匿名 提到...

坎尼你好

我想請問一下為何我將LinkButton失去作用的程式碼放到

GridView1.PageIndex=intPageIndex;

之前,LinkButton就不會正常作用了呢?

坎尼 提到...

hi 匿名,

雖然不是很了解你的情況,坎尼還是試著猜想一下:
指定完 Gridview.PageIndex 時,由於繫結著 DataSource 控制項
所以整個 Gridview 會重新 Create

把 LinkButton 控制狀態的 Method 放到這之前去,會導致因為重繪而讓已做的改變無效?

試著把 LinkButton 的 EnableViewState 設定成 true 看看,看是否還會出現問題 ^^

匿名 提到...

hi坎尼,

謝謝你,即使我描述的如此不清楚,你還是願意替我解惑

事情的起因是這樣的,我做了一個透過點選button使用textbox.text去做資料繫結的gridview,之後嫌pager太醜,打算自己作一個,因而來到坎尼的網站

坎尼是把LinkButton是否為第一和最後一頁的判別式放在pageSet(),我則是放在Query_Click()的GridView1.PageIndex=intPageIndex之後,造成分頁在第一頁時LinkButton依舊為有效,再次點選第一頁或上一頁,LinkButton才會失效

另外再請問一個問題,可能是因為我的gridview是透過Click Button動態產生,所以我的DropdownList無法用findcontrol找到,這該如何解決

期待也謝謝你的回答

坎尼 提到...

hi 匿名,

因為你把判別按鈕狀態放在 GridView1.PageIndex=intPageIndex 之後,而此時 GridView 尚未進行 DataBind() 的動作
而你再按一次判別式才成功的原因是:系統讀取的是上次的 PageIndex 狀態

所以這邊還是建議把判別按鈕狀態放在 Gridview DataBound 事件中 (本篇範例中放 pageSet 的地方)

至於要抓動態產生的 Control,抓取事件當然是要在已經動態產生之後才利用 FindControl 去抓

注意一下先後順序應該就可以解決你的問題 :D

匿名 提到...

hi坎尼

我簡單弄了一個gridview,希望你能幫我看看

protected void GridView1_DataBound(object sender, EventArgs e)
{
GridViewRow pagerRow = GridView1.BottomPagerRow;
DropDownList pageList = (DropDownList)pagerRow.Cells[0].FindControl("DropDownList1");
Label pageLabel = (Label)pagerRow.Cells[0].FindControl("Label1");

if (pageList != null)
{
for (int i = 0; i < GridView1.PageCount; i++)
{
int pageNumber = i + 1;
ListItem item = new ListItem(pageNumber.ToString());
if (i == GridView1.PageIndex)
{
item.Selected = true;
}
pageList.Items.Add(item);
}
}
if (pageLabel != null)
{
int currentPage = GridView1.PageIndex + 1;
pageLabel.Text = "Page " + currentPage.ToString() +
" of " + GridView1.PageCount.ToString();
}
}

照理說,databound應該是gridview已繫結資料才執行,gridview應該已經產生了吧(?),可是findcontrol還是會出錯

謝謝你的回答

坎尼 提到...

hi 匿名,

不知道你動態產生 Control 的 Code 寫在什麼地方?

我直接把上面那段 Code 複製貼到 DataBound 的事件中可以抓到 DropDownList (但我是事先就放在 PagerTemplate 裡)

抓不到的原因也有可能是抓錯 PagerRow
有 BottomPagerRow 和 TopPagerRow 兩種,這個也需確定一下

另外可多用中斷點來查一下原因 :)

匿名 提到...

hi坎尼

這裡不支援html標籤,我去找了圖片空間

這是我的html檔
http://thumbsnap.com/5V9ErLja
這是我的設計檢視畫面
http://thumbsnap.com/nhxhVduM
再麻煩你幫我看看

謝謝

坎尼 提到...

hi 匿名,

你的 code 看起來很正常,而且我試沒發生什麼問題 囧>

執行畫面抓圖

方便的話可以把這頁的 source code 寄給我看看嗎? 很想知道哪邊有問題 :) (點我的名字可以看到信箱)

匿名 提到...

hi坎尼

我執行的時候還是發生找不到物件的錯誤(冏很大)
檔案已寄出,屢次麻煩你真不好意思

謝謝

匿名 提到...

請問GetData(),有包含DataBind()嗎?
因為我按下一頁時,GridView1.PageIndex會是0,導致沒有資料吶!

坎尼 提到...

恩恩,如果是自己取得資料來源
需再加上 GridView.DataBind()

本篇範例是用 DataSource 控制項
由於此控制項會自動進行 Binding 的動作
故範例中並未呼叫 DataBind()

匿名 提到...

坎尼,謝謝你的回答,其實我錯誤的地方是因為我的getdata()的參數沒有接收到,才會導致沒有資料可以顯示啦~~。:p

匿名 提到...

預設GV若SqlDataSource來源資料是空的時候 會跑到EmptyTemplete 可是這個範例會無法執行 這部分大概要怎麼處理呢???

坎尼 提到...

若SqlDataSource來源資料為空時,
可以在 GridView 的 RowCreated 事件針對 EmptyTemplete 進行處理 ^^

Google Spreadsheet 裡用規則運算式

最近因為工作關係,遇到要用 Google Form 及 Google Sheet 所以研究了 Google Sheet 裡的一些 function 怎麼用 首先,分享一下如何在 Google Sheet 裡用規則運算 :D