I've been trying out the PagedList package to get paging for my index views. Everything was going well, and at the controller level everything is working fine, it only displays 5 records per page, and displays the appropriate page based on the querystring.
My problem is in the view. I changed the @Model to PagedList.IPagedList
so I could access the Model.HasNextPage
and other properties, but now the @Html.DisplayNameFor(model => model.ItemName)
are no longer working. I get this error:
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?)
Here are the relevant parts of the view:
@model PagedList.IPagedList<Dossier.Models.Item>
@using Dossier.Models.Item
...
<th>
@Html.DisplayNameFor(model => model.ItemName)
</th>
It seems IPagedList is not compatible with DisplayNameFor(). Any idea why this is happening, and how I could fix it? I know I could just manually enter the column names, but I'd like for that information to stay (and be changeable) in the model later.
You can try this
@Html.DisplayNameFor(model => model.FirstOrDefault().ItemName)
As an alternate solution to the accepted answer, remember that IPagedList inherits from IEnumerable. That means that you could write:
@model IEnumerable<Dossier.Models.Item>
At the beginning of the page, and just cast the model to IPagedList when needed:
@Html.PagedListPager((IPagedList)Model, page => Url.Action("Index", new { page = page }))
You can even declare the casted variable in the header, in order to use it multiple times within the page:
@{
ViewBag.Title = "My page title";
var pagedlist = (IPagedList)Model;
}
This would allow you to use the DisplayNameFor helper method, and access all PagedList methods/properties, without the need for dummy elements nor calling .FirstOrDefault() for each field.
I solved the problem by creating an overload of DisplayNameFor
that accepts a 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));
}
}
}
I'll be sending a pull request to PageList project to include it into the project for everyone.
You do not need to change @Html.DisplayNameFor
. Declare model in the view as:
@model IEnumerable<Dossier.Models.Item>
Just move your pager to partial view (lets name it "_Pager"):
@model IPagedList
...
@Html.PagedListPager(Model,
page => Url.Action("Index", new { page, pageSize = Model.PageSize }))
...
Render the pager in your view:
@Html.Partial("_Pager", Model)
Thats it.
P.S. You can create Html helper instead of partial view...
来源:https://stackoverflow.com/questions/14929311/using-html-displaynamefor-with-pagedlist