Thomas Bandt

Über mich | Kontakt | Archiv

ASP.NET MVC - Wiederverwendbarer Pager

Das Thema Paging (Deutsch: "Blättern") ist wohl so alt wie das World Wide Web, schließlich kann man den Usern große Listen von Daten so gut wie nie in einem Rutsch zumuten. Im aktuellen Projekt war es dann auch mal wieder so weit, Daten wollten seitenweise angezeigt und durchnavigiert werden.

Jetzt stand ich vor der Wahl ein noch aus WebForms-Zeiten stammendes, gut funktionierendes, Custom-Control zu verwenden, oder es "im MVC Style" zu machen. Irgendwie müssen ja Custom-Controls dann doch nicht mehr sein ;-). Ich stieß auf einen alten Beitrag von Robert von 2008. Seine Lösung gefielt mir damals gar nicht, irgendwie sah der Code etwas nach Nudeltopf aus. Allerdings habe ich mit dieser Art von Spaghetti-Code zu leben gelernt und finde ihn inzwischen nicht mehr wirklich schlimm. Zumindest nicht schlimmer als klassische Server-Controls mit ihren fünfhundert Templates, Attributen usw. Und die Grundlage, das Snippet von Rob Conery, habe ich so auch bereits verwendet.

Also habe ich seinen Code als Basis hergenommen und so modifiziert, dass ich einen im gesamten Projekt wiederverwendbaren Pager bekommen habe, den ich als Partial View überall einsetzen kann.

Erste Änderung: Die Properties sind aus der PagedList- in eine PagerInfo-Klasse gewandert. Somit lassen sie sich losgelöst von den eigentlichen Daten für die Generierung des Pagers verwenden, und zwar unabhängig vom verwendeten Typ der Objekte in der Liste.

   1:  public class PagedList<T> : List<T>
   2:  {
   3:   
   4:      public PagedList(IQueryable<T> source, int index, int pageSize)
   5:      {
   6:   
   7:          PagerInfo = new PagerInfo();
   8:   
   9:          PagerInfo.TotalCount = source.Count();
  10:          PagerInfo.PageSize = pageSize;
  11:          PagerInfo.PageIndex = index;
  12:   
  13:          PagerInfo.TotalPages = PagerInfo.TotalCount / pageSize;
  14:   
  15:          if (PagerInfo.TotalCount % pageSize > 0)
  16:              PagerInfo.TotalPages++;
  17:   
  18:          AddRange(source.Skip((index - 1) * pageSize).Take(pageSize).ToList());
  19:   
  20:      }
  21:   
  22:      public PagerInfo PagerInfo { get; private set; }
  23:   
  24:  }
  25:   
  26:  public class PagerInfo
  27:  {
  28:      public int TotalPages { get; set; }
  29:      public int TotalCount { get; set; }
  30:      public int PageIndex { get; set; }
  31:      public int PageSize { get; set; }
  32:      public bool HasPreviousPage { get { return (PageIndex > 1); } }
  33:      public bool HasNextPage { get { return (PageIndex * PageSize) <= TotalCount; } }
  34:  }

Als zweites habe ich einen entsprechenden Partial View angelegt, der das Rendern des Pagers übernimmt:

   1:  <ul class="pager">
   2:      <% if (Model.PagerInfo.HasPreviousPage) { %>
   3:          <li class="previous"><a href="<%= Url.Action(Model.Action, Model.Controller, new { page = Model.PagerInfo.PageIndex - 1 }) %>">« Zurück</a></li>
   4:      <% } else { %>
   5:          <li class="previous-off">« Zurück</li>
   6:      <% } %>
   7:      <%for (int page = 1; page <= Model.PagerInfo.TotalPages; page++) {
   8:          if (page == Model.PagerInfo.PageIndex) { %>
   9:          <li class="active"><%=page.ToString()%></li>
  10:          <% } else { %>
  11:              <li><a href="<%= Url.Action(Model.Action, Model.Controller, new { page }) %>"><%= page %></a></li>
  12:          <% }
  13:          } 
  14:          if (Model.PagerInfo.HasNextPage) { %>
  15:          <li class="next"><a href="<%= Url.Action(Model.Action, Model.Controller, new { page = Model.PagerInfo.PageIndex + 1 }) %>">Weiter »</a>
  16:          <% } else { %>
  17:          <li class="next-off">Weiter »</li>
  18:      <% } %>
  19:  </ul> 

Das Model beinhaltet nicht nur die "PagerInfo" sondern auch die Namen des Controllers und der Action, so dass das Ganze wiederverwendbar wird:

   1:  public class PagerViewModel
   2:  {
   3:      public PagerInfo PagerInfo { get; set; }
   4:      public string Controller { get; set; }
   5:      public string Action { get; set; }
   6:  }

Das war's im Prinzip schon, das Ergebnis kann man oben sehen. Zum Stylen kann ich genau wie Robert damals auf diesen Blogpost verweisen :-).

Anbei das Ganze als ausführbare MVC2-App.

Downloads



« Zurück  |  Weiter »