2010-01-09 10 views
15

Zastanawiam się, jak ludzie posortowali tabelę w asp.net mvc? Słyszałem o rozwiązaniach javascript, które działają całkiem dobrze z tabelami niestronicowanymi, takimi jak sorter tabel jQuery, ale potrzebuję rozwiązania, które będzie działało z tabelami stronicowanymi.Sortowanie tabeli w asp.net MVC

Projekt, nad którym obecnie pracuję, wykorzystuje następujące rozwiązanie, ale uważam, że jest bardzo brudny.

Controller

public ActionResult Sort(string parameter) 
{ 

IEnumerable<IProduct> list; 

if (Session["Model"] != null) 
    list = (IEnumerable<IProduct>)Session["Model"]).ToList<IProduct>(); 
else 
    list = _service.GetAll(); 

if (Session["parameter"] == null && Session["sortDirection"] == null) 
{ 
    //set the parameter and set the sort to desc 
    Session["parameter"] = parameter; 
    Session["sortDirection"] = "DESC"; 
} 
else if (Session["parameter"] != null) //already set so not the first time 
{ 
    //same parameter sent 
    if (Session["parameter"].ToString().Equals(parameter)) 
    { 
    //check sort direction and reverse 
    if (Session["sortDirection"].ToString().Equals("DESC")) 
    Session["sortDirection"] = "ASC"; 
    else 
    Session["sortDirection"] = "DESC"; 
    } 
    else //different parameter sent 
    { 
    Session["sortDirection"] = "DESC"; 
    Session["parameter"] = parameter; 
    } 
} 

if (Session["sortDirection"].CompareTo("ASC") == 0) 
    list = Models.ContollerHelpers.SortingHelper.OrderBy(list.AsQueryable(), column); 
else 
    list = Models.ContollerHelpers.SortingHelper.OrderByDescending(list.AsQueryable(), column); 

return View("Results", list.ToList); 
} 

Helper

public class Helper() 
{ 
private static IOrderedQueryable<T> OrderingHelper<T>(IQueryable<T> source, string propertyName, bool descending, bool anotherLevel) 
{ 
    ParameterExpression param = Expression.Parameter(typeof(T), string.Empty); // I don't care about some naming 
    MemberExpression property = Expression.PropertyOrField(param, propertyName); 
    LambdaExpression sort = Expression.Lambda(property, param); 

    MethodCallExpression call = Expression.Call(
    typeof(Queryable), 
    (!anotherLevel ? "OrderBy" : "ThenBy") + (descending ? "Descending" : string.Empty), 
    new[] { typeof(T), property.Type }, 
    source.Expression, 
    Expression.Quote(sort)); 

    return (IOrderedQueryable<T>)source.Provider.CreateQuery<T>(call); 
} 

public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName) 
{ 
    return OrderingHelper(source, propertyName, false, false); 
} 

public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string propertyName) 
{ 
    return OrderingHelper(source, propertyName, true, false); 
} 

public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string propertyName) 
{ 
    return OrderingHelper(source, propertyName, false, true); 
} 

public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string propertyName) 
{ 
    return OrderingHelper(source, propertyName, true, true); 
} 
} 

Lista Zobacz

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Models.Interface.IProduct>>" %> 
<% Session["model"] = Model; %> 
<table> 
    <tr> 
    <th> 
    Edit Details 
    </th> 
    <th> 
    <%=Html.ActionLink("Id","Sort",new {parameter ="Id"}) %> 
    </th> 
    <th> 
    <%=Html.ActionLink("Name", "Sort", new { parameter = "Name"})%> 
    </th> 
    <th> 
    <%=Html.ActionLink("Status", "Sort", new { parameter = "Status" })%> 
    </th> 
    <th> 
    <%=Html.ActionLink("Notes", "Sort", new { parameter = "Notes"})%> 
    </th> 
    </tr> 
    <% foreach (var item in Model){ %> 

    <tr> 
    <td> 
    <%= Html.ActionLink("Edit", "Edit", new { id=item.Id }) %> | 
    </td> 
    <td> 
    <%= Html.Encode(item.Id) %> 
    </td> 
    <td> 
    <%= Html.Encode(item.Name) %> 
    </td> 
    <td> 
    <%= Html.Encode(item.Status) %> 
    </td> 
    <td> 
    <%= Html.Encode(item.Notes) %> 
    </td> 
    </tr> 

    <% } %> 
    </table> 

Jest to jedyny sposób na d coś takiego? Jeśli ktoś wie o ładniejszym sposobie, który nie wymaga jednoczesnego załadowania wszystkich rekordów na stronę, wówczas należy połączyć się z przykładami.

+0

@AlteredConcept q jest zbyt szeroka, że ​​u nie mówią, co u są najbardziej zainteresowani. Czy jest to widok (raczej, skoro jest dość prosty), sposób sortowania w sposób ogólny za pomocą linq, użycie sesji do przechowywania parametrów, użycie "parametru" takiego jak to lub jego parsowanie. – eglasius

+0

Przepraszam za to. Kontroler jest tym, co najbardziej mi przeszkadza. Nie chcę powtarzać całego tego kodu w każdym kontrolerze dla każdego widoku listy encji. To dużo powielania kodu. Próbowałem znaleźć sposób, w jaki mógłbym umieścić to w kontrolerze bazowym, ale uruchamiał puste miejsce. Tak więc szukałem, aby zobaczyć, czy inni mają ładniejsze, bardziej eleganckie podejście do sortowania – AlteredConcept

+0

Dzięki. Boli mnie głowa. –

Odpowiedz

10

Sprawdź DataTables @DataTables to pozwoli Ci strona wynik i kwerendy go z łatwej konfiguracji. działa dobrze z danymi ajax i json. Spójrz na próbki. Mam nadzieję, że ci to pomoże.

+0

+1. Z powodzeniem wykorzystałem wtyczkę jQuery DataTables w aplikacji ASP.NET MVC z przetwarzaniem po stronie serwera (http://datatables.net/usage/server-side). –

+2

Spowoduje to załadowanie wszystkich danych na stronę podczas ładowania (nawet jeśli strona ładuje się po załadowaniu). Spróbuj załadować ponad 1000 rekordów naraz. Zanim strona zostanie wyświetlona, ​​minie trochę czasu. – AlteredConcept

+1

Użyj przetwarzania po stronie serwera, aby wysyłać tylko wiersze, które są wyświetlane na stronie http://datatables.net/usage/server-side klienta, jak zauważył Antoni. –

7

Spróbuj jednej z następujących metod rozszerzenia (od czubka głowy):

static class OrderByExtender 
{ 
    public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> collection, string key, string direction) 
    { 
     LambdaExpression sortLambda = BuildLambda<T>(key); 

     if(direction.ToUpper() == "ASC") 
      return collection.OrderBy((Func<T, object>)sortLambda.Compile()); 
     else 
      return collection.OrderByDescending((Func<T, object>)sortLambda.Compile()); 
    } 

    public static IOrderedEnumerable<T> ThenBy<T>(this IOrderedEnumerable<T> collection, string key, string direction) 
    { 
     LambdaExpression sortLambda = BuildLambda<T>(key); 

     if (direction.ToUpper() == "ASC") 
      return collection.ThenBy((Func<T, object>)sortLambda.Compile()); 
     else 
      return collection.ThenByDescending((Func<T, object>)sortLambda.Compile()); 
    } 

    private static LambdaExpression BuildLambda<T>(string key) 
    { 
     ParameterExpression TParameterExpression = Expression.Parameter(typeof(T), "p"); 
     LambdaExpression sortLambda = Expression.Lambda(Expression.Convert(Expression.Property(TParameterExpression, key), typeof(object)), TParameterExpression); 
     return sortLambda; 
    } 
} 

Zastosowanie:

var products = Session["Model"] as IEnumerable<Product>() ?? _service.GetAll(); 

return products.OrderBy("Name", "ASC").ThenBy("Price", "DESC"); 

Zakładając cię tylko używasz stan 1 orderby naraz można użyć:

var products = Session["Model"] as IEnumerable<Product>(); 

var sortDirection = Session["Direction"] as string ?? "DESC"; 
Session["Direction"] = sortDirection == "DESC" ? "ASC" : "DESC"; 
sortDirection = Session["Direction"] as string; 

return products.OrderBy(parameter, sortDirection); 
+0

Czy kierunek.ToLower() nie powinien być kierunkiem.ToUpper()? – AlteredConcept

+0

Prawidłowo. Dzięki za wskazanie tego, napisałem to w notatniku :-) –

+0

Bez problemu. Podoba mi się to podejście, ale mam pewne problemy z tym związane. Czasami sortuje się poprawnie, a innym razem - nie (zamiast wznosić się maleje i na odwrót). – AlteredConcept

4

Jeśli JavaScript jest wyłączony, oznacza to, że masz problem.

Wybrałbym rozwiązanie noscript.

bym dwie grupy przycisków radiowych:

direction: () ascending (.) descending 

orderBy: (.) Id () Name () Status 

bym traktować View jako formie z wieloma przedłożyć przyciski:

(bez JavaScriptu) ~~ samą nazwę dla obu przycisków.

na Twoim.strona aspx, dodać trzy przyciski:

<input type="submit" value="Requery" name="submitButton"/> 
<input type="submit" value="Previous" name="submitButton"/> 
<input type="submit" value="Next"  name="submitButton"/> 

w Controller:

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Sort(string direction, string orderBy, string submitButton) 
{ 
    if (submitButton == "Requery")  //et cetera 

TMTOWTDI: Jest więcej niż jeden sposób, aby to zrobić

0

Zdecydowanie podoba Jana rozwiązanie - wielkie dzięki lot Jan ... Właśnie uratowałeś mi około 60 linii kodu z analizą przypadku analizującą każdy z nagłówków kolumn. Rozwiązanie "robi świetne przełączanie, tylko sortowanie według 1 kolumny na tabelach", gdy używane są dwie zmienne sesji, jedna do zachowania ASC/DESC jako wartości logicznej i jedna do przechowywania nazwy typu/kolumny.

Wykorzystałem to rozszerzenie z przykładu C# i wdrożyłem je z VB po południu. Udało mi się wyciąć 30-liniowy opis sprawy w jeden wiersz kodu.

na widok:

<th>Date <a class="clickable" href="<%=Url.Action("SortStationVisits", New With {.SortField = "PlanningDate"})%>"><span class="colSort" style="display: inline-table;"></span></a></th> 

przedłużenie (Moduł publiczny OrderByExtender):

Imports System.Linq.Expressions 

Public Function OrderBy(Of T)(collection As IEnumerable(Of T), key As String, isDescending As Boolean) As IOrderedEnumerable(Of T) 
    Dim sortLambda As LambdaExpression = BuildLambda(Of T)(key) 
    If isDescending Then 
     Return collection.OrderByDescending(DirectCast(sortLambda.Compile(), Func(Of T, Object))) 
    Else 
     Return collection.OrderBy(DirectCast(sortLambda.Compile(), Func(Of T, Object))) 
    End If 
End Function 

Public Function ThenBy(Of T)(collection As IOrderedEnumerable(Of T), key As String, isDescending As Boolean) As IOrderedEnumerable(Of T) 
    Dim sortLambda As LambdaExpression = BuildLambda(Of T)(key) 

    If (isDescending) Then 
     Return collection.ThenByDescending(DirectCast(sortLambda.Compile(), Func(Of T, Object))) 
    Else 
     Return collection.ThenBy(DirectCast(sortLambda.Compile(), Func(Of T, Object))) 
    End If 
End Function 

Private Function BuildLambda(Of T)(key As String) As LambdaExpression 
    Dim TParameterExpression As ParameterExpression = Expression.Parameter(GetType(T), "p") 
    Dim sortLambda As LambdaExpression = Expression.Lambda(Expression.Convert(Expression.[Property](TParameterExpression, key), GetType(Object)), TParameterExpression) 
    Return sortLambda 
End Function 

NA DZIAŁANIE Kontroler:

Public Function SortStationVisits(Optional page As Integer = 1, Optional SortField As String = "") As ActionResult 
    Dim sps = LoadSession() 

    If SortField = sps.StationVisitSorter Then 
     sps.StationVisitDescOrder = Not (sps.StationVisitDescOrder) 
    Else 
     sps.StationVisitDescOrder = False 
    End If 

    sps.StationVisitSorter = SortField 

    SaveSession(sps) 
    Return RedirectToAction("Show") 
End Function 

na regulatorze SHOW SPOSÓB (1 linia kodu w00t!):

spv.SelectableStationVisits = spv.SelectableStationVisits.OrderBy(sps.StationVisitSorter, sps.StationVisitDescOrder).ToList