The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

ASP.NET MVC 開發心得分享 (5):顯示資料分頁(MvcPaging)

分享到噗浪!

在網頁上進行表格資料或其他顯示資料的分頁是一種十分常見的需求,以前我們有 GridView 或 DataPager 可以幫我們自動分頁,雖然到了 ASP.NET MVC 一切全部重頭來過,但我們也不用真的那麼辛苦的自己實做分頁,因為早就有人幫我們寫好程式並開放原始碼分享給這個世界了。

如果你已經體會到在 ASP.NET MVC 中妥善利用強型別(Strong Typed)特性進行開發的優點時,你將會發現搭配 Visual Studio 2008 進行專案開發的過程有多美妙。以下我先舉一個簡單的例子:

---

你可以在 Controller 中定義一個 Action 方法,並在裡面先取得所有需顯示在 View 中的資料,如果你用 LINQ to SQL 的話,可以直接傳入 IQueryable 型別的物件到 View 中,當成 View 裡面使用的 Model,這樣可以享受延遲載��(Defered Loading) 的效果。

public ActionResult Index()
{
	IQueryable<Customer> custs =   
		from cust in db.Customers   
		where cust.City == "Taiwan"
		select cust; 
		
	return View(custs);
}

之後在你的 View 中宣告繼承時可透過泛型指派 IQueryable<Customer> 進去:

<%@ Page Language="C#" 
         Inherits="System.Web.Mvc.ViewPage<IQueryable<Customer>>" %>

或是轉型成統一個 IEnumable<Customer> ,這也是比較常見的用法:

<%@ Page Language="C#" 
         Inherits="System.Web.Mvc.ViewPage<IEnumable<Customer>>" %>

然後你就可以利用 foreach 取出所有資料並將資料顯示出來了:

<table>
<% foreach (var item in Model) { %>
<tr>
	<td><%= Html.Encode(item.ID) %></td>
	<td><%= Html.Encode(item.Name) %></td>
	<td><%= Html.Encode(item.Tel) %></td>
</tr>
<% } %>
</table>

這就是標準的 ASP.NET MVC 取得資料並顯示在 View 中的 Pattern。

---

我們最近在開發 ASP.NET MVC 專案的過程中,除了自行研究如何有效分頁以外,也上網找了好幾套 ASP.NET MVC 分頁的解決方案,最後我們總結出一個最好用的就是這個元件 ( Paging with ASP.NET MVC )。

要利用這個元件進行資料分頁,不外乎有幾件事必須做到:

  1. 需傳入一個 page 參數到 Action 中,用以指定你目前要顯示「第幾頁」的資料。
  2. 準備傳入的資料(Model),可透過 Paging with ASP.NET MVC 元件中提供的 Extension Method 將 IList<T>, IQueryable<T>, 或 IEnumable<T> 型別的資料轉換成 IPagedList<T> 的型別,並傳入 View 中。
  3. 透過一個自訂的 Html Helper 在 View 中必須顯示「分頁導覽列」的資訊 (如下圖)
    分頁導覽列

依據上面三個步驟進行修改,Action 的程式碼會變成這樣:

// 分頁後每頁顯示的筆數
int defaultPageSize = 10;

// 傳入 page 參數 ( 透過 Model Binder 綁進來的 )
public ActionResult Index(int? page)
{
	IQueryable<Customer> custs =   
		from cust in db.Customers   
		where cust.City == "Taiwan"
		select cust; 
	
	// 計算出目前要顯示第幾頁的資料 ( 因為 page 為 Nullable<int> 型別 )
	int currentPageIndex = page.HasValue ? page.Value - 1 : 0;

	// 透過 ToPagedList 這個 Extension Method 將原本的資料轉成 IPagedList<T>
	return View(custs.ToPagedList(currentPageIndex, defaultPageSize));
}

然後在 View 中顯示資料的地方,透過一個自訂的 Html Helper 方法顯示分頁資訊。

首先必須先修改傳入 View 的 Model 型別

<%@ Page Language="C#" 
         Inherits="System.Web.Mvc.ViewPage<IPagedList<Customer>>" %>

然後再宣告匯入 MvcPaging 命名空間,好讓 Html.Pager 這個 Html Helper Method 可以使用:
備註: 也可以在 web.config 設定,請參考 ASP.NET 如何預設匯入指定的命名空間(Namespace) 文章!

<%@ Import Namespace="MvcPaging"%>

然後原本顯示資料的程式「完全不用改寫」,只要加上「分頁導覽列」即可:

<table>
<% foreach (var item in Model) { %>
<tr>
	<td><%= Html.Encode(item.ID) %></td>
	<td><%= Html.Encode(item.Name) %></td>
	<td><%= Html.Encode(item.Tel) %></td>
</tr>
<% } %>
</table>

<div class="pager">
<%= Html.Pager(Model.PageSize, Model.PageNumber, Model.TotalItemCount) %>
</div>

就這樣簡單幾個步驟即可完成 ASP.NET MVC 內的分頁了,是不是還不錯用呢!

相關連結

評論 (18) -

  • demo

    2009/3/22 上午 08:42:18 |

    對於這種有系統的文我還不太會發...

  • Ausir

    2009/3/22 上午 09:13:58 |

    .net 不會用

    不過我最近也在看一些 MVC 的東西

    corAusir 程式逗設計  - 提供設計資料與程式設計 -

    blog.corausir.org

    或 點我的名字參觀喔

  • 花米

    2009/5/9 下午 12:11:43 |

    此分页有Bug
    在分页 Pager.cs 中修改
                    /*
                     * i == this.currentPage 因为在分页中是从0开始的,但是在页面显示是从1开始的,所以这里需要+1
                     */
                    if (i == this.currentPage+1)
                    {
                        sb.AppendFormat("<span class=\"current\">{0}</span>", i);
                    }
                    else
                    {
                        sb.Append(GeneratePageLink(i.ToString(), i));
                    }
    你觉得呢?

  • demo

    2009/5/10 上午 01:03:42 |

    他有分為 PageNumber 和PageIndex

  • 花米

    2009/5/21 下午 09:09:47 |




    //分析Pager.cs
    //本段生成分页链接
    //start 首页 =PageNumber=1
    //end 总页数  
    //this.currentPage 当前页(注:第一页时为0,我自己认为)
    /*
    will 也是这样认为的
    // 計算出目前要顯示第幾頁的資料 ( 因為 page 為 Nullable<int> 型別 )
      int currentPageIndex = page.HasValue ? page.Value - 1 : 0;

    */
    for (int i = start; i <= end; i++)
    {
    /*我认为
    * i == this.currentPage 因为在分页中是从0开始的,但是在页面显示是从1开始的,所以这里需要+1
    */
                    if (i == this.currentPage+1 /*是我加的 +1*/)
            {
    //当前页,蓝色部分
              sb.AppendFormat("<span class=\"current\">{0}</span>", i);
            }
            else
            {
    //其他页,非蓝色部分
              sb.Append(GeneratePageLink(i.ToString(), i));
            }
          }

  • Will 保哥

    2009/12/17 上午 02:24:26 |

    星寂:

    Thanks! 已修復!

  • Jerry

    2010/12/21 上午 01:11:47 |

    您好!

    我照您的書去做分頁,可是執行後出現:

    '/' 應用程式中發生伺服器錯誤。
    這個物件沒有定義無參數的建構函式。

    請問這是MvcPaging有問題嗎
    還是Global.asax 也要設定?

  • 小叶

    2011/8/29 上午 12:31:30 |

    保兄,你好,请问mvc3的分页怎么做,razor格式的,按mvcpager控件怎么弄,01.<%@ Page Language="C#"    
    02.         Inherits="System.Web.Mvc.ViewPage<IPagedList<Customer>>" %>  
    怎么转化,<%@ Import Namespace="MvcPaging"%>  等等,不胜感激!!!

  • 小叶

    2011/8/29 上午 12:34:30 |

    补充:我用脚手架创建新闻列表,暂时不需要过滤功能

  • dragon1111

    2012/9/14 上午 02:04:33 |

    保哥 您好!

    方便請教一下 MvcPaging 中將資料轉換成 IPagedList<T>
    是屬於僅取回分頁所需資料的有效分頁
    亦或是取回所有資料後 , 但僅顯示部分分頁的可視性分頁?
    經常拜讀您的大作 獲益良多 感恩!

  • 兔子

    2012/9/18 上午 12:42:20 |

    您好:

    謝謝您的範例,對我們很有幫助

    請教一下,
    若要在同一個View中顯示多個Model時
    分頁該如何處理,

    例如類似這樣的ViewModel包含兩個原先是 IEnumable<T>轉成的IPagedList<T>:
    public class TxViewModel2
        {
            public IPagedList<Customer> CustomerList { get; set; }
            public IPagedList<Product> ProductList { get; set; }
        }

    在View中做分頁的處理時,使用強行別TxViewModel2
    但執行頁面時點選頁碼,卻會導回到首頁去
    我該如何讓我的View()辨別他該走到CustomerList的第二頁
    或是ProductList的第二頁

    謝謝您指點迷津



  • 小肥

    2013/3/8 下午 11:16:13 |

    保哥你好,我的網頁顯示為
    <span class="disabled">&lt;</span><span class="current">1</span><a href="/Dinner?page=2">2</a><a href="/Dinner?page=2">&gt;</a>
    應該是jquery append在html建立標籤後才加入程式碼,所以會沒辦法轉成html語法,請問該如何解決?

  • armykong

    2013/3/13 下午 07:03:18 |

    第1版我發現有點小問題:若每頁10頁,總資料共11/12/13時,會有點問題,所以加了一點小修正在Pager.cs(約81行的位置),有相同現像的人可以參考

    if (end < (pageCount - 3))
    {
    sb.Append("...");
    sb.Append(GeneratePageLink((pageCount - 1).ToString(), pageCount - 1));
    sb.Append(GeneratePageLink(pageCount.ToString(), pageCount));
    }
    else
    {
        //add here ...補剩餘總頁數
        for (var i = end + 1; i < pageCount+1; i++)
        {
           sb.Append(GeneratePageLink(i.ToString(), i));
                        
        }
      }

  • Will 保哥

    2013/3/21 上午 07:07:06 |

    armykong: 給你按個讚! Smile

  • Steven

    2014/3/17 下午 06:55:12 |

    請問
    像MVCPageing裡面是可以自定DisplayTemplate,
    我想說我自己做的一些套件,想加上這種功能,
    完全有什麼樣的資料可以看,還是方向?

blog comments powered by Disqus