2012年7月11日 星期三

ASP.NET MVC 資料分頁 MVCPaging 2.0 應用 - 使用 DisplayTemplate 設定分頁樣式

這幾天接連好幾篇介紹 MvcPaging 2.0 的應用,從一般的分頁、AJAX 分頁,最後是使用 jQuery 的 AJAX 分頁,幾乎都把 MvcPaging 2.0 的基本應用都給介紹完了,但其實還有一樣沒有介紹,那就是自訂分頁樣式,這是 MvcPagin 2.0 的一個新功能「DisplayTemplate」,我們可以設定一個 Template 的 PartialView,這個 PartialView 是用來產生 Pager,而產生 Pager 的方法則是使用寫在 View Page 上面的 Razor @helper,有別於以往產生 Pager 內容是必須要從後端的方式,在前端使用 Razor @helper 來產生 Pager 會更為容易。

 


回顧一下,之前我們如果想要依據需求去客製分頁列的樣式時,我們是需要在後端去新增一個 Method,由這個 Method 來產生 Pager 內容,

這個我在以前的文章有做作過介紹:

ASP.NET MVC - 資料分頁(2) 自訂分頁功能列 MvcSimplePager

ASP.NET MVC - 資料分頁(3) 自訂分頁功能列 MvcSimplePostPager

 

在後端的 Method 去產生一個客製 Pager,其實不是那麼容易,所以當分頁有比較特殊的需求要解決時,就會比較麻煩,所以 MvcPaging 2.0 就利用了 ASP.NET MVC 3 Razor 的一個功能「Razor @helper」來解決這樣的問題,什麼是「Razor @helper」呢?這邊不多做說明,而是提供幾篇文章的連結,讓大家有個概念與了解,

ScottGu’s Blog - ASP.NET MVC 3 and the @helper syntax within Razor

ScottGu的中文部落格 - ASP.NET MVC 3和Razor中的@helper 語法

天空的垃圾場  -  ASP.NET MVC – Razor的@helper語法

 

其實在 twMVC 第一場的研討會中也曾經由 Dino 介紹過 Razor @helper,

活動詳細資訊「 twMVC - 2012_04_26 與 ASP.NET MVC 的第一次親密接觸

 


接下來就來說明如何使用 DisplayTemplate 以顯示並使用客製的 Pager 樣式內容,這邊的程式範本是使用「ASP.NET MVC 資料分頁 MVCPaging 2.0 應用 Part.4:分頁進階處理」(PagedAjax2),各位可以到「ASP.NET MVC 資料分頁 MVCPaging 2.0 應用 - 範例程式下載」裡去下載範例程式。

 

複製 PagedAjax2 的程式內容,並且另外建立一個新的 Action 方法,

#region -- PagedTemplate --
        
public ActionResult PagedTemplate()
{
    int currentPageIndex = 0;
 
    this.PrepareDropDownLists(this.FilterCity, this.SortColumnName, this.SortType);
    this.SearchSolumnDropDownList(string.Empty);
 
    ViewData.Model = this.allCustomers.ToPagedList(currentPageIndex, DefaultPageSize);
    return View();
}
 
public ActionResult PagedTemplatePartial(int? page,
    string keyword,
    string searchColumn,
    string city = "all",
    string sortColumnName = "CustomerID",
    string sort = "asc")
{
    int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
 
    this.FilterCity = city;
    this.SortColumnName = sortColumnName;
    this.SortType = sort;
 
    ViewBag.Keyword = keyword;
    ViewBag.DisplaySortColumnLink = new Func<string, MvcHtmlString>(SortColumnLink);
 
    using (NorthwindEntities db = new NorthwindEntities())
    {
        var query = db.Customers.Select(x => x);
 
        if (!string.IsNullOrWhiteSpace(keyword))
        {
            string queryExpression = string.Format("{0}.Contains(@0)", searchColumn);
            query = query.Where(queryExpression, keyword);
        }
        if (!city.Equals("all"))
        {
            query = query.Where("City == @0", city ?? "London");
        }
        query = query.OrderBy(string.Format("{0} {1}", sortColumnName, sort));
 
        ViewData.Model = query.ToPagedList(currentPageIndex, DefaultPageSize);
    }
 
    return PartialView("_PagedTemplate");
} 
#endregion

分別建立好 View Page 以及 PartialView Page

「PagedTemplate.cshtml」

@model IPagedList<MvcMSSQL.Models.Customer>
@{
    ViewBag.Title = "Advanced - PagedAjax - DisplayTemplated";
    Layout = "~/Views/Shared/_LayoutTemplate.cshtml";
}
 
<h2>Advanced - PagedAjax - DisplayTemplated</h2>
<fieldset>
    <br />
    City:@ViewData["CityDDL"] 
    Saerch Column:@ViewData["SearchColumnDDL"] 
    Contains <input type="text" id="keyword" name="keyword" value="@ViewBag.Keyword" /> 
    <input type="hidden" id="sortColumnName" value="CustomerID" />
    <input type="hidden" id="sort" value="asc" />
    <input type="button" value="Submit" id="ButtonSubmit" /> 
    <input type="button" value="Reset" id="ButtonReset" />
</fieldset>
 
<div id="gridcontainer">
</div>
 
@if (false){ <script src="../../Scripts/jquery-1.7.2.min.js" type="text/javascript"></script> }
<script type="text/javascript">
<!--
    $(document).ready(function () {
        $('#ButtonSubmit').click(function () { ButtonSubmitEventHandler(); });
        $('#ButtonReset').click(function () { ButtonResetEventHandler(); });
    });
 
    function ButtonResetEventHandler() {
        $('#city').removeAttr('disabled');
        $('#searchColumn').removeAttr('disabled');
        $('#searchColumn option:eq(0)').attr('selected', true);
        $('#keyword').removeAttr('disabled').val('');
        $('#sortColumnName').val('CustomerID');
        $('#sort').val('asc');
 
        $('#gridcontainer').empty();
    }
 
    function ButtonSubmitEventHandler() {
        var cityValue = $('#city option:selected').val();
        var searchColumnValue = $('#searchColumn option:selected').val();
        var keywordValue = $.trim($('#keyword').val());
 
        var sortColumnValue = $('#sortColumnName').val();
        var sortValue = $('#sort').val();
 
        $.ajax({
            url: '@Url.Action("PagedTemplatePartial", "Advanced")',
            data: { keyword: keywordValue, searchColumn: searchColumnValue, city: cityValue, sortColumnName: sortColumnValue, sort: sortValue },
            type: 'post',
            async: false,
            cache: false,
            dataType: 'html',
            success: function (data) {
                $('#gridcontainer').html(data);
 
                $('#city').attr('disabled', true);
                $('#sortColumnName').attr('disabled', true);
                $('#sort').attr('disabled', true);
                $('#searchColumn').attr('disabled', true);
                $('#keyword').attr('disabled', true);
            }
        });
    }
 
    function postPage(page) {
        var cityValue = $('#city option:selected').val();
        var searchColumnValue = $('#searchColumn option:selected').val();
        var keywordValue = $.trim($('#keyword').val());
 
        var sortColumnValue = $('#sortColumnName').val();
        var sortValue = $('#sort').val();
 
        $.ajax({
            url: '@Url.Action("PagedTemplatePartial", "Advanced")',
            data: { page: page, keyword: keywordValue, searchColumn: searchColumnValue, city: cityValue, sortColumnName: sortColumnValue, sort: sortValue },
            type: 'post',
            async: false,
            cache: false,
            dataType: 'html',
            success: function (data) {
                $('#gridcontainer').html(data);
 
                $('#city').attr('disabled', true);
                $('#sortColumnName').attr('disabled', true);
                $('#sort').attr('disabled', true);
                $('#searchColumn').attr('disabled', true);
                $('#keyword').attr('disabled', true);
            }
        });
    };
 
-->
</script>

「_PagedTemplate.cshtml」

@model PagedList<MvcMSSQL.Models.Customer>
 
@if (Model != null && Model.Count > 0)
{
    <div class="pager">
        @Html.Pager(Model.PageSize, Model.PageNumber, Model.TotalItemCount).Options(o => o
            .DisplayTemplate("PagerTemplate")
            .MaxNrOfPages(10)) 
        
         | 第 @Model.PageNumber 頁 / 共 @Model.PageCount 頁 | 顯示第 @Model.ItemStart - @Model.ItemEnd 項資料 / 共 @Model.TotalItemCount 項 |
    </div>
    <br />
    
    <table>
        <thead>
            <th>
                @ViewBag.DisplaySortColumnLink("CompanyName")
            </th>
            <th>
                @ViewBag.DisplaySortColumnLink("ContactName")
            </th>
            <th>
                @ViewBag.DisplaySortColumnLink("ContactTitle")
            </th>
            <th>
                @ViewBag.DisplaySortColumnLink("Address")
            </th>
            <th>
                @ViewBag.DisplaySortColumnLink("City")
            </th>
            <th>
                @ViewBag.DisplaySortColumnLink("Region")
            </th>
            <th>
                @ViewBag.DisplaySortColumnLink("PostalCode")
            </th>
            <th>
                @ViewBag.DisplaySortColumnLink("Country")
            </th>
            <th>
                @ViewBag.DisplaySortColumnLink("Phone")
            </th>
            <th>
                @ViewBag.DisplaySortColumnLink("Fax")
            </th>
        </thead>
        <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @item.CompanyName
                </td>
                <td>
                    @item.ContactName
                </td>
                <td>
                    @item.ContactTitle
                </td>
                <td>
                    @item.Address
                </td>
                <td>
                    @item.City
                </td>
                <td>
                    @item.Region
                </td>
                <td>
                    @item.PostalCode
                </td>
                <td>
                    @item.Country
                </td>
                <td>
                    @item.Phone
                </td>
                <td>
                    @item.Fax
                </td>
            </tr>
        }
        </tbody>
    </table>
}
 
@if (false)
{ <script src="../../Scripts/jquery-1.7.2.min.js" type="text/javascript"></script> }
 
<script type="text/javascript">
    $(document).ready(function () {
        $('.pager> a').each(function (i, item) {
            if ($(item).attr('href') != '#'){
                var page = $(item).attr('href').replace('@(Url.Action("PagedTemplatePartial", "Advanced"))?page=', '');
                $(item).attr('href', '#').click(function () { postPage(page); });
            }
        });
 
        $('[class="sortColumnLink"]').each(function (i, item) {
            var sortColumnName = $(item).attr('href');
            var sortType = $(item).attr('id').replace(sortColumnName + "_", "");
            var currentStyle = $(item).attr('style');
            if ($.trim(currentStyle).length > 0) {
                sortType = sortType == 'asc' ? 'desc' : 'asc';
            }
 
            $(item).attr('href', '#').click(function () {
                $('#sortColumnName').val(sortColumnName);
                $('#sort').val(sortType);
                ButtonSubmitEventHandler();
            });
        });
    });
</script>

 

在「_PagedTemplate.cshtml」中要注意到的是 pager 的內容設定,

<div class="pager">
    
    @Html.Pager(Model.PageSize, Model.PageNumber, Model.TotalItemCount).Options(o => o
        .DisplayTemplate("PagerTemplate")
        .MaxNrOfPages(10))
    | 第 @Model.PageNumber 頁 / 共 @Model.PageCount 頁 | 顯示第 @Model.ItemStart - @Model.ItemEnd 項資料 / 共 @Model.TotalItemCount 項 |
</div>

在 Html.Pager() 的 Oprions 設定內容裡,我們在 DisplayTemplate() 中指定了一個 Template 的 PartialView,另外也有設定了 MaxNrOrPages(),其值為 10,「MaxNrOrPages」這可以讓我們設定每次分頁最多可以顯示幾頁,而如果沒有設定 MaxNrOrPages() 的話,預設值本身就是為 10。

 

DisplayTemplate 的 PartialView 內容

這個 Template 的 PartialView 檔案可以建立在 Views > Shared 目錄下,必須建立一個目錄「DisplayTemplate」(只能使用這個目錄名稱),然後再把 Pager 的 Template PartialView 檔案放在底下,

image

其實也可以把這個 DisplayTemplates 的目錄與檔案放在 Controller 所對應的 Views 子目錄下,但因為這個 Template 檔案會是屬於與其他 Controller 與 View Page 可以共用的,所以還是建議放在「Views > Shared」目錄下會比較好。

 

接下來就看這個 Template Partial View 檔案的內容,

「Views > Shared > DisplayTemplate > PagerTemplate.cshtml

   1:  @model PaginationModel
   2:   
   3:  @BuildFirstLink()
   4:   
   5:  @foreach (var link in Model.PaginationLinks)
   6:  {
   7:      @BuildLink(link)
   8:  }
   9:   
  10:  @BuilderLastLink()
  11:   
  12:   
  13:  @helper BuildFirstLink()
  14:  {
  15:      if (Model.PaginationLinks.Count > 0)
  16:      {
  17:          <a href="1">最前頁</a>
  18:      }
  19:  }
  20:   
  21:  @helper BuilderLastLink()
  22:  {
  23:      if (Model.PaginationLinks.Count > 0)
  24:      {
  25:          <a href="@Html.Raw(Model.PaginationLinks.Count.ToString())">最後頁</a> 
  26:      }
  27:  }
  28:   
  29:  @helper BuildLink(PaginationLink link)
  30:  {
  31:      var aBuilder = new TagBuilder("a");
  32:      if (link.Url == null)
  33:      {
  34:          aBuilder.MergeAttribute("href", "#");
  35:      }
  36:      else
  37:      {
  38:          aBuilder.MergeAttribute("href", link.Url);
  39:      }
  40:   
  41:      if (link.IsCurrent)
  42:      {
  43:          aBuilder.MergeAttribute("class", "current");
  44:      }
  45:   
  46:      if (link.DisplayText == "«")
  47:      {
  48:          aBuilder.SetInnerText("上一頁");
  49:      @Html.Raw(aBuilder.ToString())
  50:      }
  51:      else if (link.DisplayText == "»")
  52:      {
  53:          aBuilder.SetInnerText("下一頁");
  54:      @Html.Raw(aBuilder.ToString())
  55:      }
  56:      else if (link.DisplayText == "...")
  57:      {
  58:      @Html.Raw(" ... ")
  59:      }
  60:      else
  61:      {
  62:          aBuilder.SetInnerText(link.DisplayText);
  63:          @Html.Raw(aBuilder.ToString())
  64:      }    
  65:  }

PagerTemplate.cshtml」就是使用了 Razor @helper 來產生 Pager 的分頁連結內容,程式內容我就不再贅述,很淺白的程式內容,相信大家都可以了解。

 

最後就來看看程式執行的結果吧!

 

一開始的執行畫面

image

 

顯示資料內容與 Pager 內容

image

 

在下面兩張圖所框起來的部分,這是要說明「MaxNrOrPages」的設定所產生的結果,

image

image

如果是分頁碼是在全部頁數的中間的話,則是產生如下圖的樣式,不會超過 10 個分頁連結,

image

 

這一篇文章說明 MvcPaging 2.0 所提供的 DisplayTemplate 功能,讓我們可以客製 Pager 的顯示樣式與內容。

 


參考連結

github – MvcPaging

https://github.com/martijnboland/MvcPaging

 

以上

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。