2013-02-18 9 views
41

Ho provato il pacchetto PagedList per ottenere il paging per le visualizzazioni dell'indice. Tutto andava bene e, a livello di controller, tutto funziona perfettamente, visualizza solo 5 record per pagina e visualizza la pagina appropriata in base alla querystring.Utilizzo di @ Html.DisplayNameFor() con PagedList

Il mio problema è nella vista. Ho modificato @Model in PagedList.IPagedList in modo da poter accedere allo Model.HasNextPage e ad altre proprietà, ma ora lo @Html.DisplayNameFor(model => model.ItemName) non funziona più. Ottengo questo errore:

PagedList.IPagedList<Dossier.Models.Item>' does not contain a definition for 'ItemName' and no extension method 'ItemName' accepting a first argument of type 'PagedList.IPagedList<Dossier.Models.Item>' could be found (are you missing a using directive or an assembly reference?)

Qui ci sono le parti pertinenti della vista:

@model PagedList.IPagedList<Dossier.Models.Item> 
@using Dossier.Models.Item 

... 

<th> 
    @Html.DisplayNameFor(model => model.ItemName) 
</th> 

Sembra IPagedList non è compatibile con DisplayNameFor(). Qualche idea sul perché questo sta accadendo e su come potrei risolverlo? So che potrei semplicemente inserire manualmente i nomi delle colonne, ma mi piacerebbe che tali informazioni restassero (ed essere modificabili) nel modello più tardi.

+0

Perché non utilizzare ViewBag per trasportare i dati e lasciare @model come era in origine? –

risposta

71

Si può provare questo

@Html.DisplayNameFor(model => model.FirstOrDefault().ItemName) 
+0

Grazie, questo l'ha risolto. –

+32

L'uso di 'First()' genererà un 'InvalidOperationException' quando non ci sono elementi nella sequenza. L'uso di 'FirstOrDefault()' evita questa eccezione. Oppure potresti usare un elemento fittizio 'FirstOrDefault', come suggerito in questa domanda duplicata: http://stackoverflow.com/a/13780314/1364650 –

+0

@viniciusdeLemos: anche questo è risolto il mio problema :) – Zafar

29

Come soluzione alternativa per la risposta accettata, si ricordi che IPagedList eredita da IEnumerable. Ciò significa che si potrebbe scrivere:

@model IEnumerable<Dossier.Models.Item> 

All'inizio della pagina, e basta lanciare il modello da IPagedList quando necessario:

@Html.PagedListPager((IPagedList)Model, page => Url.Action("Index", new { page = page })) 

si può anche dichiarare la variabile fuso nell'intestazione, in per usarlo più volte all'interno della pagina:

@{ 
    ViewBag.Title = "My page title"; 
    var pagedlist = (IPagedList)Model; 
} 

Ciò consentirebbe di utilizzare il metodo di supporto DisplayNameFor, e accedere a tutte PagedList metodi/proprietà, senza la necessità di elementi fittizi né chiamare .FirstOrDefault() per ogni campo.

+1

Un anno dopo e questo soluzione funziona ancora. Di tutte le risposte presentate, questa è stata la più utile per me perché (a) ha funzionato, e (b) è breve e semplice. –

+0

Questa dovrebbe essere la risposta - Funziona alla grande –

+1

Questa è la soluzione più pulita. –

4

Ho risolto il problema creando un sovraccarico di DisplayNameFor che accetta uno IPagedList<TModel>.

namespace PagedList.Mvc 
{ 
    public static class Extensions 
    { 

     [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] 
     public static MvcHtmlString DisplayNameFor<TModel, TValue>(this HtmlHelper<IPagedList<TModel>> html, Expression<Func<TModel, TValue>> expression) 
     { 
      return DisplayNameForInternal(html, expression); 
     } 

     [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This is an extension method")] 
     internal static MvcHtmlString DisplayNameForInternal<TModel, TValue>(this HtmlHelper<IPagedList<TModel>> html, Expression<Func<TModel, TValue>> expression) 
     { 
      return DisplayNameHelper(ModelMetadata.FromLambdaExpression(expression, new ViewDataDictionary<TModel>()), 
            ExpressionHelper.GetExpressionText(expression)); 
     } 

     internal static MvcHtmlString DisplayNameHelper(ModelMetadata metadata, string htmlFieldName) 
     { 
      string resolvedDisplayName = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last(); 

      return new MvcHtmlString(HttpUtility.HtmlEncode(resolvedDisplayName)); 
     } 
    } 
} 

Invierò una richiesta di pull al progetto PageList per includerlo nel progetto per tutti.

0

Non è necessario modificare @Html.DisplayNameFor. Dichiarare modello nella vista come:

@model IEnumerable<Dossier.Models.Item> 

Basta muovere il cercapersone di vista parziale (lascia il nome "_Pager"):

@model IPagedList 

... 

@Html.PagedListPager(Model, 
    page => Url.Action("Index", new { page, pageSize = Model.PageSize })) 

... 

rendere il cercapersone nella vista:

@Html.Partial("_Pager", Model) 

Questo è tutto.

P.S. È possibile creare helper HTML anziché vista parziale ...