2013-02-18 2 views
41

Я пробовал пакет PagedList, чтобы получить пейджинг для моих представлений индексов. Все шло хорошо, и на уровне контроллера все работает нормально, оно отображает только 5 записей на странице и отображает соответствующую страницу на основе запроса.Использование @ Html.DisplayNameFor() с PagedList

Моя проблема во взгляде. Я изменил @Model на PagedList.IPagedList, чтобы получить доступ к Model.HasNextPage и другим объектам, но теперь @Html.DisplayNameFor(model => model.ItemName) больше не работают. Я получаю эту ошибку:

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?)

Вот соответствующие части представления:

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

... 

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

Это кажется IPagedList не совместим с DisplayNameFor(). Любая идея, почему это происходит, и как я могу это исправить? Я знаю, что могу просто вручную ввести имена столбцов, но мне хотелось бы, чтобы эта информация оставалась (и менялась) в модели позже.

+0

Почему бы не использовать ViewBag для переноса ваших данных и оставить @model так, как он был изначально? –

ответ

71

Вы можете попробовать это

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

Спасибо, это исправлено. –

+32

Использование 'First()' будет вызывать 'InvalidOperationException', когда в последовательности нет элементов. Использование 'FirstOrDefault()' исключает это исключение. Или вы можете использовать фиктивный элемент 'FirstOrDefault' ', как это предлагается в этом дублирующем вопросе: http://stackoverflow.com/a/13780314/1364650 –

+0

@viniciusdeLemos: это тоже исправлено :) – Zafar

29

В качестве альтернативного решения принятого ответа, помните, что IPagedList наследуется от IEnumerable. Это означает, что вы могли бы написать:

@model IEnumerable<Dossier.Models.Item> 

В начале страницы, а просто привести модель в IPagedList при необходимости:

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

Вы даже можете объявить с приведением переменной в заголовке, в для того, чтобы использовать его несколько раз в пределах страницы:

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

Это позволит вам использовать вспомогательный метод DisplayNameFor, и получить доступ ко всем PagedList методы/свойства, без необходимости фиктивные элементы и вызов FirstOrDefault() для каждого поля.

+1

Год спустя и этот решение по-прежнему работает. Из всех представленных ответов этот был наиболее полезен для меня, потому что (а) он работал, и (б) он короткий и простой. – 2015-06-24 15:08:35

+0

Это должен быть ответ - отлично работает –

+1

Это похоже на самое чистое решение. –

4

Я решил проблему, создав перегрузку DisplayNameFor, что принимает 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)); 
     } 
    } 
} 

Я отправлю запрос на тягу в проект PageList, чтобы включить его в проект для всех.

0

Вам не нужно изменять @Html.DisplayNameFor. Объявить модели в представлении, как:

@model IEnumerable<Dossier.Models.Item> 

Просто переместите пейджера на частичный вид (позволяет назвать его "_Pager"):

@model IPagedList 

... 

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

... 

Рендер пейджера на ваш взгляд:

@Html.Partial("_Pager", Model) 

Thats it.

P.S. Вы можете создать помощник Html вместо частичного представления ...

Смежные вопросы