ASP.NET WebGrid

Optimale Verwendung von WebGrid in ASP.NET MVC

Stuart Leeks

Beispielcode herunterladen.

Dieses Jahr hat Microsoft ASP.NET MVC Version 3 (asp.net/mvc) und ein neues Produkt mit dem Namen WebMatrix (asp.net/webmatrix) veröffentlicht. Die WebMatrix-Version umfasste eine Reihe von Hilfsfunktionen für Produktivität, um Aufgaben wie das Rendern von Diagrammen und Tabellendaten zu vereinfachen. Mit einer dieser Hilfsfunktionen, WebGrid, können Sie Tabellendaten auf sehr einfache Weise rendern, und benutzerdefinierte Formatierung von Spalten, Paginierung, Sortierung und asynchrone Updates per AJAX werden unterstützt.

In diesem Artikel stelle ich WebGrid vor und zeige die Verwendung in ASP.NET MVC 3. Anschließend wird erläutert, wie in Verbindung mit einer ASP.NET MVC-Lösung der größte Nutzen erzielt werden kann. (Eine Übersicht über WebMatrix – und die in diesem Artikel verwendete Razor-Syntax – finden Sie im Artikel "Einführung in WebMatrix" von Clark Sell in der April 2011-Ausgabe unter msdn.microsoft.com/magazine/gg983489).

In diesem Artikel wird untersucht, wie Sie die WebGrid-Komponente in eine ASP.NET MVC-Umgebung integrieren, um beim Rendern von Tabellendaten eine hohe Produktivität zu erzielen. Ich werde WebGrid aus der ASP.NET MVC-Perspektive betrachten: Erstellung einer stark typisierten Version von WebGrid mit voller IntelliSense-Unterstützung, Verknüpfung mit der WebGrid-Unterstützung für serverseitiges Paging und Hinzufügen der AJAX-Funktionalität, die ordnungsgemäß heruntergestuft wird, wenn die Skripterstellung deaktiviert wird. Die Arbeitsbeispiele werden auf Grundlage eines Diensts erstellt, der den Zugriff auf die AdventureWorksLT-Datenbank über das Entity Framework gewährt. Falls Sie Interesse am Datenzugriffscode haben, können Sie ihn über den Codedownload herunterladen. Es ist auch ratsam, den Artikel "Serverseitige Auslagerung mithilfe des Entity Framework und ASP.NET MVC 3" von Julie Lerman in der März 2011-Ausgabe zu lesen (msdn.microsoft.com/magazine/gg650669).

Erste Schritte mit WebGrid

Um ein einfaches Beispiel für WebGrid zeigen zu können, habe ich eine ASP.NET MVC-Aktion eingerichtet, die einfach ein "IEnumerable<Product>"-Element an die Ansicht übergibt. In diesem Artikel verwende ich größtenteils das Razor-Ansichtsmodul, aber später erläutere ich auch, wie Sie das WebForms-Ansichtsmodul einsetzen können. Meine ProductController-Klasse verfügt über die folgende Aktion:

public ActionResult List()
  {
    IEnumerable<Product> model =
      _productService.GetProducts();
 
    return View(model);
  }

Die Listenansicht enthält den folgenden Razor-Code, mit dem das in Abbildung 1 dargestellte Raster gerendert wird:

    @model IEnumerable<MsdnMvcWebGrid.Domain.Product>
    @{
      ViewBag.Title = "Basic Web Grid";
    }
    <h2>Basic Web Grid</h2>
    <div>
    @{
      var grid = new WebGrid(Model, defaultSort:"Name");
    }
    @grid.GetHtml()
    </div>

A Basic Rendered Web Grid
(Zum Vergrößern auf das Bild klicken)

Abbildung 1: Grundlegendes gerendertes Webraster

In der ersten Zeile der Ansicht wird der Modelltyp (z. B. der Typ der "Model"-Eigenschaft, auf den in der Ansicht zugegriffen wird) als "IEnumerable<Product>" angegeben. Innerhalb des "div"-Elements wird dann ein WebGrid-Element instanziiert, und die Modelldaten werden übergeben. Ich führe dies in einem "@{...}"-Codeblock durch, damit Razor weiß, dass das Ergebnis nicht gerendert werden soll. Im Konstruktor lege ich den Parameter "defaultSort" außerdem auf "Name" fest, damit WebGrid weiß, dass die übergebenen Daten bereits nach Name sortiert sind. Schließlich verwende ich "@grid.GetHtml()", um die HTML-Daten für das Raster zu generieren und in der Antwort zu rendern.

Diese geringe Menge an Code bietet eine umfassende Rasterfunktionalität. Das Raster beschränkt die Menge der angezeigten Daten und enthält Paginierungslinks zum Navigieren durch die Daten. Spaltenüberschriften werden als Links gerendert, um die Paginierung zu ermöglichen. Sie können im WebGrid-Konstruktor und in der "GetHtml"-Methode eine Reihe von Optionen angeben, um dieses Verhalten anzupassen. Mithilfe der Optionen können Sie die Paginierung und Sortierung deaktivieren, die Anzahl der Zeilen pro Seite ändern, den Text in den Paginierungslinks ändern und weitere Schritte durchführen. Abbildung 2 zeigt die Parameter des WebGrid-Konstruktors und Abbildung 3 die "GetHtml"-Parameter.

Abbildung 2: WebGrid-Konstruktorparameter

Name Typ Hinweise
Quelle IEnumerable<dynamic> Die zu rendernden Daten.
columnNames IEnumerable<string> Filtert die Spalten, die gerendert werden.
defaultSort string Gibt die Spalte an, nach der standardmäßig sortiert wird.
rowsPerPage int Steuert, wie viele Zeilen pro Seite gerendert werden (Standard ist 10).
canPage bool Aktiviert oder deaktiviert die Paginierung von Daten.
canSort bool Aktiviert oder deaktiviert die Sortierung von Daten.
ajaxUpdateContainerId string Die ID des enthaltenden Elements des Rasters, über das die AJAX-Unterstützung aktiviert wird.
ajaxUpdateCallback string Die clientseitige Funktion, die aufgerufen wird, wenn das AJAX-Update abgeschlossen ist.
fieldNamePrefix string Präfix für Abfragezeichenfolgen-Felder zur Unterstützung mehrerer Raster.
pageFieldName string Abfragezeichenfolgen-Feldname für die Seitenzahl.
selectionFieldName string Abfragezeichenfolgen-Feldname für die ausgewählte Zeilennummer.
sortFieldName string Abfragezeichenfolgen-Feldname für die Sortierspalte.
sortDirectionFieldName string Abfragezeichenfolgen-Feldname für die Sortierrichtung.

Abbildung 3: "WebGrid.GetHtml"-Parameter

Name Typ Hinweise
tableStyle string Tabellenklasse für den Tabellenstil.
headerStyle string Kopfzeilenklasse für Stile.
footerStyle string Fußzeilenklasse für Stile.
rowStyle string Zeilenklasse für Stile (nur ungerade Zeilen).
alternatingRowStyle string Zeilenklasse für Stile (nur gerade Zeilen).
selectedRowStyle string Klasse für den Stil ausgewählter Zeilen.
caption string Die als Tabellentitel angezeigte Zeichenfolge.
displayHeader bool Gibt an, ob die Kopfzeile angezeigt werden soll.
fillEmptyRows bool Gibt an, ob die Tabelle leere Zeilen hinzufügen kann, um die "rowsPerPage"-Zeilenanzahl sicherzustellen.
emptyRowCellValue string Wert zum Auffüllen leerer Zeilen. Wird nur verwendet, wenn "fillEmptyRows" festgelegt ist.
columns IEnumerable<WebGridColumn> Spaltenmodell zum Anpassen des Renderings von Spalten.
exclusions IEnumerable<string> Spalten, die beim automatischen Auffüllen von Spalten ausgeschlossen werden.
mode WebGridPagerModes Renderingmodi für die Paginierung (Standard ist "NextPrevious" und "Numeric").
firstText string Text für einen Link zur ersten Seite.
previousText string Text für einen Link zur vorherigen Seite.
nextText string Text für einen Link zur nächsten Seite.
lastText string Text für einen Link zur letzten Seite.
numericLinksCount int Anzahl der anzuzeigenden numerischen Links (Standard ist 5).
htmlAttributes object Enthält die HTML-Attribute, die für das Element festgelegt werden.

Der obige Razor-Code rendert alle Eigenschaften für jede Zeile, aber Sie können einschränken, welche Spalten angezeigt werden. Hierfür gibt es eine Reihe von Möglichkeiten: Die erste (und einfachste) Möglichkeit ist das Übergeben der Gruppe von Spalten an den WebGrid-Konstruktor. Mit diesem Code werden z. B. nur die Eigenschaften "Name" und "ListPrice" gerendert:

var grid = new WebGrid(Model, columnNames: new[] {"Name", "ListPrice"});

Sie können die Spalten auch im Aufruf von "GetHtml" angeben, anstatt im Konstruktor. Dies ist zwar etwas länger, hat jedoch den Vorteil, dass Sie zusätzliche Informationen angeben können, wie die Spalten gerendert werden sollen. Im folgenden Beispiel habe ich die "header"-Eigenschaft angegeben, um die Spalte "ListPrice" benutzerfreundlicher zu gestalten:

@grid.GetHtml(columns: grid.Columns(
 grid.Column("Name"),
 grid.Column("ListPrice", header:"List Price")
 )
)

Beim Rendern einer Liste mit Elementen möchten Sie es sicherlich häufig ermöglichen, dass Benutzer auf ein Element klicken können, um zur Ansicht "Details" zu navigieren. Mit dem Parameter "format" der "Column"-Methode können Sie das Rendering eines Datenelements anpassen. Der folgende Code zeigt, wie Sie das Rendering von Namen ändern, um für ein Element einen Link zur Ansicht "Details" auszugeben. Außerdem wird der Listenpreis mit zwei Dezimalstellen ausgegeben, wie dies bei Währungsbeträgen üblich ist. Die sich ergebende Ausgabe ist in Abbildung 4 dargestellt.

@grid.GetHtml(columns: grid.Columns(
 grid.Column("Name", format: @<text>@Html.ActionLink((string)item.Name,
            "Details", "Product", new {id=item.ProductId}, null)</text>),
 grid.Column("ListPrice", header:"List Price", 
             format: @<text>@item.ListPrice.ToString("0.00")</text>)
 )
)

A Basic Grid with Custom Columns

Abbildung 4: Einfaches Raster mit benutzerdefinierten Spalten

Obwohl es so aussieht, als ob beim Angeben des Formats Magie im Spiel ist, ist der Parameter "format" eigentlich nur ein "Func<dynamic,object>"-Element – ein Delegat, der einen dynamischen Parameter verwendet und ein Objekt zurückgibt. Das Razor-Modul ändert den für den Parameter "format" angegebenen Codeausschnitt in einen Delegaten. Dieser Delegat erfordert einen dynamischen Parameter mit dem Namen "item". Dies ist die Elementvariable, die im "format"-Codeausschnitt verwendet wird. Weitere Informationen zur Funktionsweise dieser Delegaten finden Sie im Blogeintrag von Phil Haack unter bit.ly/h0Q0Oz.

Da der Parameter "item" einen dynamischen Typ aufweist, wird beim Schreiben von Code keine IntelliSense- oder Compilerprüfung durchgeführt (siehe Artikel von Alexandra Rusina zu dynamischen Typen in der Februar 2011-Ausgabe unter msdn.microsoft.com/magazine/gg598922). Außerdem wird das Aufrufen von Erweiterungsmethoden mit dynamischen Parametern nicht unterstützt. Aus diesem Grund müssen Sie beim Aufrufen von Erweiterungsmethoden sicherstellen, dass Sie statische Typen verwenden. Daher wird "item.Name" in eine Zeichenfolge umgewandelt, wenn ich im vorherigen Code die "Html.ActionLink"-Erweiterungsmethode aufrufe. Bei den vielen Erweiterungsmethoden, die in ASP.NET MVC verwendet werden, kann dieser Konflikt zwischen dynamischen Methoden und Erweiterungsmethoden zur Last werden (dies gilt besonders, wenn Sie Tools wie T4MVC verwenden: bit.ly/9GMoup).

Hinzufügen von starker Typisierung

Die dynamische Typisierung eignet sich wahrscheinlich gut für WebMatrix, aber eine stark typisierte Ansicht hat ebenfalls Vorteile. Eine Möglichkeit, dies zu erreichen, ist das Erstellen eines "WebGrid<T>"-Elements mit abgeleitetem Typ, wie in Abbildung 5 dargestellt. Sie sehen, dass es sich um einen ziemlich einfachen Wrapper handelt.

Abbildung 5: Erstellen eines abgeleiteten WebGrid-Elements

public class WebGrid<T> : WebGrid
  {
    public WebGrid(
      IEnumerable<T> source = null,
      ... parameter list omitted for brevity)
    : base(
      source.SafeCast<object>(), 
      ... parameter list omitted for brevity)
    { }
  public WebGridColumn Column(
              string columnName = null, 
              string header = null, 
              Func<T, object> format = null, 
              string style = null, 
              bool canSort = true)
    {
      Func<dynamic, object> wrappedFormat = null;
      if (format != null)
      {
        wrappedFormat = o => format((T)o.Value);
      }
      WebGridColumn column = base.Column(
                    columnName, header, 
                    wrappedFormat, style, canSort);
      return column;
    }
    public WebGrid<T> Bind(
            IEnumerable<T> source, 
            IEnumerable<string> columnNames = null, 
            bool autoSortAndPage = true, 
            int rowCount = -1)
    {
      base.Bind(
           source.SafeCast<object>(), 
           columnNames, 
           autoSortAndPage, 
           rowCount);
      return this;
    }
  }

  public static class WebGridExtensions
  {
    public static WebGrid<T> Grid<T>(
             this HtmlHelper htmlHelper,
             ... parameter list omitted for brevity)
    {
      return new WebGrid<T>(
        source, 
        ... parameter list omitted for brevity);
    }
  }

Was erreichen wir damit? Bei der neuen "WebGrid<T>"-Implementierung habe ich eine neue "Column"-Methode hinzugefügt, die ein "Func<T, object>"-Element für den Parameter "format" verwendet. Dies bedeutet, dass die Umwandlung beim Aufrufen von Erweiterungsmethoden nicht erforderlich ist. Außerdem ist jetzt eine IntelliSense- und Compilerprüfung möglich (vorausgesetzt, in der Projektdatei ist "MvcBuildViews" aktiviert; standardmäßig deaktiviert).

Mithilfe der "Grid"-Erweiterungsmethode können Sie den Typrückschluss des Compilers für generische Parameter nutzen. In diesem Beispiel können Sie also "Html.Grid(Model)" anstelle von "new WebGrid<Product>(Model)" schreiben. In beiden Fällen lautet der zurückgegebene Typ "WebGrid<Product>".

Hinzufügen von Paginierung und Sortierung

Sie haben bereits gesehen, dass Sie mit WebGrid ohne jeden weiteren Aufwand Paginierungs- und Sortierungsfunktionen erhalten. Sie haben auch erfahren, wie Sie die Seitengröße mit dem Parameter "rowsPerPage" so konfigurieren (im Konstruktor oder über das "Html.Grid"-Hilfselement), dass das Raster automatisch eine einzelne Seite mit Daten anzeigt und die Paginierungssteuerelemente zum Navigieren zwischen Seiten gerendert werden. Es kann jedoch sein, dass das Standardverhalten nicht dem von Ihnen gewünschten Verhalten entspricht. Um dies zu veranschaulichen, habe ich Code hinzugefügt, mit dem nach dem Rendern des Rasters die Anzahl der Elemente in der Datenquelle gerendert wird. Dies ist in Abbildung 6 dargestellt.

The Number of Items in the Data Source

Abbildung 6: Anzahl der Elemente in der Datenquelle

Wie Sie sehen, umfassen die übergebenen Daten die gesamte Liste der Produkte (in diesem Beispiel 295, aber es sind Szenarios vorstellbar, in denen auch deutlich mehr Daten abgerufen werden). Wenn sich die Menge der zurückzugebenden Daten erhöht, steigt auch die Belastung Ihrer Dienste und Datenbanken, während weiterhin nur die eine Seite mit Daten gerendert wird. Es gibt jedoch einen besseren Ansatz: die serverseitige Paginierung. In diesem Fall werden nur die Daten abgerufen, die zum Anzeigen der aktuellen Seite erforderlich sind (z. B. nur fünf Zeilen).

Der erste Schritt beim Implementieren der serverseitigen Paginierung für WebGrid ist das Beschränken der Datenmenge, die aus der Datenquelle abgerufen wird. Dazu müssen Sie wissen, welche Seite angefordert wird, damit die richtige Seite mit Daten abgerufen werden kann. Beim Rendern der Paginierungslinks verwendet WebGrid erneut die Seiten-URL und fügt daran einen Abfragezeichenfolgen-Parameter mit der Seitenzahl an, z. B. "http://localhost:27617/Product/DefaultPagingAndSorting?page=3" (der Abfragezeichenfolgen-Parameter kann über die Hilfsparameter konfiguriert werden, was nützlich ist, falls Sie die Paginierung für mehr als ein Raster auf einer Seite unterstützen möchten). Dies bedeutet, dass Sie einen Parameter mit dem Namen "page" in Ihrer Aktionsmethode verwenden können, die dann mit dem Wert der Abfragezeichenfolge aufgefüllt wird.

Falls Sie nur den vorhandenen Code zum Übergeben einer einzelnen Seite mit Daten an WebGrid ändern, sieht WebGrid nur eine einzelne Seite mit Daten. Weil keine Informationen vorhanden sind, dass weitere Seiten existieren, werden keine Paginierungssteuerelemente mehr gerendert. Glücklicherweise verfügt WebGrid über eine andere Methode mit dem Namen "Bind", die Sie zum Angeben der Daten verwenden können. "Bind" akzeptiert nicht nur die Daten, sondern besitzt auch einen Parameter, der anhand der Gesamtzahl der Zeilen die Anzahl an Seiten berechnet. Um diese Methode verwenden zu können, muss die "List"-Aktion so aktualisiert werden, dass sie die zusätzlich an die Ansicht zu übergebenden Informationen abruft. Dies ist in Abbildung 7 dargestellt.

Abbildung 7: Aktualisieren der "List"-Aktion

public ActionResult List(int page = 1)
{
  const int pageSize = 5;
 
  int totalRecords;
  IEnumerable<Product> products = productService.GetProducts(
    out totalRecords, pageSize:pageSize, pageIndex:page-1);
            
  PagedProductsModel model = new PagedProductsModel
                                 {
                                   PageSize= pageSize,
                                   PageNumber = page,
                                   Products = products,
                                   TotalRows = totalRecords
                                 };
  return View(model);
}

Mit diesen zusätzlichen Informationen kann die Ansicht so aktualisiert werden, dass sie die "WebGrid Bind"-Methode verwendet. Mit dem Aufruf von "Bind" werden die zu rendernden Daten und die Gesamtzahl der Zeilen bereitgestellt. Außerdem wird der Parameter "autoSortAndPage" auf "false" festgelegt. Mit dem Parameter "autoSortAndPage" wird WebGrid angewiesen, dass keine Paginierung angewendet werden muss, weil die "List"-Aktionsmethode dies übernimmt. Der folgende Code veranschaulicht dies:

    <div>
    @{
      var grid = new WebGrid<Product>(null, rowsPerPage: Model.PageSize, 
        defaultSort:"Name");
      grid.Bind(Model.Products, rowCount: Model.TotalRows, autoSortAndPage: false);
    }
    @grid.GetHtml(columns: grid.Columns(
     grid.Column("Name", format: @<text>@Html.ActionLink(item.Name, 
       "Details", "Product", new { id = item.ProductId }, null)</text>),
      grid.Column("ListPrice", header: "List Price", 
        format: @<text>@item.ListPrice.ToString("0.00")</text>)
      )
     )
     
    </div>

Nachdem diese Änderungen vorgenommen wurden, erwacht WebGrid wieder zum Leben und rendert die Paginierungssteuerelemente. Die Paginierung wird jedoch im Dienst durchgeführt, nicht in der Ansicht! Da "autoSortAndPage" deaktiviert ist, ist die Sortierfunktion aber nicht verfügbar. In WebGrid werden Abfragezeichenfolgen-Parameter verwendet, um die zu sortierende Spalte und die Richtung zu übergeben, aber wir haben das Programm angewiesen, keine Sortierung durchzuführen. Dies kann behoben werden, indem der Aktionsmethode die Parameter "sort" und "sortDir" hinzugefügt und diese an den Dienst übergeben werden, damit dieser die erforderliche Sortierung durchführen kann. Dies ist in Abbildung 8 dargestellt.

Abbildung 8: Hinzufügen von Sortierungsparametern zur Aktionsmethode

public ActionResult List(
           int page = 1, 
           string sort = "Name", 
           string sortDir = "Ascending" )
{
  const int pageSize = 5;
 
  int totalRecords;
  IEnumerable<Product> products =
    _productService.GetProducts(out totalRecords,
                                pageSize: pageSize,
                                pageIndex: page - 1,
                                sort:sort,
                                sortOrder:GetSortDirection(sortDir)
                                );
 
  PagedProductsModel model = new PagedProductsModel
  {
    PageSize = pageSize,
    PageNumber = page,
    Products = products,
    TotalRows = totalRecords
  };
  return View(model);
}

AJAX: Clientseitige Änderungen

WebGrid unterstützt die asynchrone Aktualisierung des Rasterinhalts mit AJAX. Dazu müssen Sie lediglich sicherstellen, dass das "div"-Element, in dem das Raster enthalten ist, über eine ID verfügt. Diese ID muss im Parameter "ajaxUpdateContainerId" an den Konstruktor des Rasters übergeben werden. Sie benötigen auch einen Verweis auf "jQuery", aber der ist in der Layoutansicht bereits enthalten. Wenn die ID unter "ajaxUpdateContainerId" angegeben wird, modifiziert WebGrid das Verhalten so, dass für die Links zur Paginierung und Sortierung bei Aktualisierungen AJAX verwendet wird:

    <div id="grid">
     
    @{
      var grid = new WebGrid<Product>(null, rowsPerPage: Model.PageSize, 
      defaultSort: "Name", ajaxUpdateContainerId: "grid");
      grid.Bind(Model.Products, autoSortAndPage: false, rowCount: Model.TotalRows);
    }
    @grid.GetHtml(columns: grid.Columns(
     grid.Column("Name", format: @<text>@Html.ActionLink(item.Name, 
       "Details", "Product", new { id = item.ProductId }, null)</text>),
     grid.Column("ListPrice", header: "List Price", 
       format: @<text>@item.ListPrice.ToString("0.00")</text>)
     )
    )
     
    </div>

Die integrierten Funktionen zur Verwendung von AJAX sind gut, aber die generierte Ausgabe funktioniert nicht, falls das Scripting deaktiviert ist. Der Grund ist, dass WebGrid im AJAX-Modus Ankertags rendert, für die "href" auf "#" festgelegt ist, und das AJAX-Verhalten über den onclick-Handler injiziert.

Ich bin immer bestrebt, Seiten zu erstellen, die ordnungsgemäß heruntergestuft werden, wenn das Scripting deaktiviert ist. Im Allgemeinen lässt sich dies am besten mithilfe einer progressiven Verbesserung erreichen (im Grunde genommen eine Seite, die ohne Scripting funktioniert, aber durch das Hinzufügen von Scripting erweitert wird). Um dies umzusetzen, können Sie auf WebGrid ohne AJAX zurückgreifen und das in Abbildung 9 dargestellte Skript zum erneuten Anwenden des AJAX-Verhaltens erstellen:

Abbildung 9: Erneutes Anwenden des AJAX-Verhaltens

$(document).ready(function () {
 
  function updateGrid(e) {
    e.preventDefault();
    var url = $(this).attr('href');
    var grid = $(this).parents('.ajaxGrid'); 
    var id = grid.attr('id');
    grid.load(url + ' #' + id);
  };
  $('.ajaxGrid table thead tr a').live('click', updateGrid);
  $('.ajaxGrid table tfoot tr a').live('click', updateGrid);
 });

Um die ausschließliche Anwendung des Skripts auf ein WebGrid-Element zuzulassen, werden jQuery-Selektoren zum Identifizieren von Elementen mit dem "ajaxGrid"-Klassensatz verwendet. Mit dem Skript werden onclick-Ereignishandler für die Sortierungs- und Paginierungslinks (Identifizierung über Tabellenkopf oder –fuß im "grid"-Container) mithilfe der "live"-jQuery-Methode eingerichtet (api.jquery.com/live). So wird der Ereignishandler für vorhandene und zukünftige Elemente eingerichtet, die die Kriterien des Selektors erfüllen. Dies ist nützlich, weil das Skript den Inhalt ersetzt.

Die "updateGrid"-Methode wird als Ereignishandler festgelegt, und die erste Aktion ist das Aufrufen von "preventDefault", um das Standardverhalten zu unterdrücken. Danach wird die zu verwendende URL abgerufen (aus dem "href"-Attribut im Ankertag) und ein AJAX-Aufruf durchgeführt, um den aktualisierten Inhalt in das Containerelement zu laden. Stellen Sie bei diesem Ansatz sicher, dass das WebGrid-AJAX-Standardverhalten deaktiviert ist, fügen Sie dem div-Containerelement die "ajaxGrid"-Klasse hinzu, und fügen Sie dann das Skript aus Abbildung 9 ein.

AJAX: Serverseitige Änderungen

Ein weiterer wichtiger Punkt ist, dass im Skript eine Funktion der "load"-jQuery-Methode verwendet wird, um ein Fragment des zurückgegebenen Dokuments zu isolieren. Wenn Sie einfach "load(‘http://example.com/someurl’)" aufrufen, wird der unter der URL vorhandene Inhalt geladen. Bei "load(‘http://example.com/someurl #someId’)" wird jedoch der Inhalt der angegebenen URL geladen und dann das Fragment mit der ID "someId" zurückgegeben. Dies ist eine Nachbildung des AJAX-Standardverhaltens von WebGrid. Sie müssen Ihren Servercode also nicht aktualisieren, um Verhalten für partielles Rendering hinzuzufügen. WebGrid lädt die gesamte Seite und löst das neue Raster heraus.

Wenn es um die schnelle Nutzung der AJAX-Funktionalität geht, ist dies hilfreich. Sie übermitteln dabei jedoch mehr Daten als nötig und schlagen wahrscheinlich auch mehr Daten als nötig auf dem Server nach. Glücklicherweise erleichtert ASP.NET MVC den Umgang hiermit sehr. Die grundlegende Idee besteht darin, das Rendering, das in AJAX- und Nicht-AJAX-Anforderungen freigegeben werden soll, in eine Teilansicht zu extrahieren. Mit der "List"-Aktion im Controller kann dann entweder nur die Teilansicht für AJAX-Aufrufe oder die Gesamtansicht (die wiederum die Teilansicht verwendet) für die Nicht-AJAX-Aufrufe gerendert werden.

Der Ansatz kann so einfach wie das Testen des Ergebnisses der "Request.IsAjaxRequest"-Erweiterungsmethode aus Ihrer Aktionsmethode heraus sein. Dies kann gut funktionieren, falls zwischen den AJAX- und Nicht-AJAX-Codepfaden nur sehr geringe Unterschiede bestehen. Häufig bestehen jedoch größere Unterschiede (z. B. erfordert das vollständige Rendering mehr Daten als das partielle Rendering). In diesem Fall würden Sie wahrscheinlich ein "AjaxAttribute" schreiben, um separate Methoden schreiben zu können, und dann das MVC-Framework in Abhängigkeit davon die richtige Methode wählen lassen, ob die Anforderung eine AJAX-Anforderung ist (so funktionieren auch die Attribute "HttpGet" und "HttpPost"). Ein Beispiel hierzu finden Sie in meinem Blogeintrag unter bit.ly/eMlIxU.

WebGrid und das WebForms-Ansichtsmodul

Bisher wurde in allen Beispielen das Razor-Ansichtsmodul verwendet. Im einfachsten Fall müssen Sie keine Änderungen vornehmen, um WebGrid mit dem WebForms-Ansichtsmodul zu verwenden (abgesehen von Unterschieden bei der Ansichtsmodulsyntax). In den obigen Beispielen habe ich gezeigt, wie Sie das Rendering von Zeilendaten mit dem Parameter "format" anpassen können:

grid.Column("Name", 
  format: @<text>@Html.ActionLink((string)item.Name, 
  "Details", "Product", new { id = item.ProductId }, null)</text>),

Der Parameter "format" ist eigentlich ein "Func"-Element, aber das Razor-Ansichtsmodul blendet dies aus. Sie können jedoch auch ein "Func"-Element übergeben. Beispielsweise können Sie einen Lambda-Ausdruck verwenden:

grid.Column("Name", 
  format: item => Html.ActionLink((string)item.Name, 
  "Details", "Product", new { id = item.ProductId }, null)),

Ausgestattet mit dieser einfachen Umstellung können Sie WebGrid jetzt problemlos mit dem "WebForms"-Ansichtsmodul nutzen.

Zusammenfassung

In diesem Artikel habe ich verdeutlicht, wie Sie mithilfe einiger einfacher Änderungen die Funktionen von WebGrid nutzen können, ohne auf starke Typisierung, IntelliSense oder eine effiziente serverseitige Paginierung verzichten zu müssen. WebGrid verfügt über einige hervorragende Funktionen, mit der Sie beim Rendern von Tabellendaten Ihre Produktivität steigern können. Ich hoffe, dieser Artikel konnte Ihnen ein Gefühl dafür vermitteln, wie Sie die Vorteile in einer ASP.NET MVC-Anwendung am besten nutzen können.

Stuart Leeks ist Application Development Manager im Premier Support for Development-Team in Großbritannien. Er hat eine übertriebene Vorliebe für Tastenkombinationen. Sein Blog finden Sie unter blogs.msdn.com/b/stuartleeks. Darin schreibt er über technische Themen, die ihn interessieren (z. B. ASP.NET MVC, Entity Framework, LINQ und mehr).

Unser Dank gilt den folgenden technischen Experten für die Durchsicht dieses Artikels: Simon Ince und Carl Nolan