@Html.DisplayNameFor for details model

2019-03-17 20:02发布

In my model I have an Entity

public class Carrier
{
public Guid CarrierId { get; set; }
public string Name { get; set; }
}

I also have a ViewModel

public class CarrierIndexViewModel
{
public IEnumerable<Carrier> Carriers { get; set; }
public PagingInfo PagingInfo { get; set; }
}

I have a strongly-typed (CarrierIndexViewModel) Index View, which is suppose to display a table of Carrier using PagingInfo.

I'm trying to use Html helper to display Carrier.Name in my table's header When I used IEnumerable as a model for this view I had @Html.DisplayFor(model => model.Name)

How can I get same result using my new CarrierIndexViewModel to display title for Carrier.Name?

5条回答
虎瘦雄心在
2楼-- · 2019-03-17 20:41

You can add a @using statement to your View to specify the Carrier type, then you will need to loop through your Model's Carriers property.

Your View will look something like..

@model CarrierIndexViewModel
@using Carrier

@foreach(Carrier c in Model.Carriers)
{
 @Html.DisplayFor(model => c.Name)
}
查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-03-17 20:52

I had a similar requirement, but I needed to get display names for properties from a different non-enumerable class so the solution from @plurby wouldn't have worked. I ended up solving this by creating a fluent call that can be used to get a new HtmlHelper for any arbitrary type. The code for the extension and adapter is:

public static class HtmlHelpers
{
    public static HtmlHelperAdapter<TModel> Adapt<TModel>(this HtmlHelper<TModel> helper)
    {
        return new HtmlHelperAdapter<TModel>(helper);
    }

    public class HtmlHelperAdapter<TModel>
    {
        private readonly HtmlHelper<TModel> _helper;

        public HtmlHelperAdapter(HtmlHelper<TModel> helper)
        {
            _helper = helper;
        }

        public HtmlHelper<TNewModel> For<TNewModel>()
        {
            return new HtmlHelper<TNewModel>(_helper.ViewContext, new ViewPage(), _helper.RouteCollection);
        }
    }
}

You can then use this in the view like this:

<td>@(Html.Adapt().For<MyOtherModel>().DisplayNameFor(m => m.SomeProperty))</td>

One of the advantages is that this approach will work for any HtmlHelper extension, not just DisplayNameFor (but keep in mind that the adapted HtmlHelper does not have any view data since that's all typed based on the model being used in the view and thus won't work in the adapted HtmlHelper).

查看更多
走好不送
4楼-- · 2019-03-17 20:55

I found there was no need for helper methods, extra code or looping through the collection. I just used the following:

@Html.DisplayNameFor(model => model.Carriers.FirstOrDefault().Name)

This still works even if FirstOrDefault() would return null because it's only looking for meta data, the Name property itself is not accessed.

Many thanks to @Kurian who inspired this answer.

查看更多
来,给爷笑一个
5楼-- · 2019-03-17 20:58

Here is an approach, which is based on the original DisplayNameFor extension method and works consistent.

An extension method for HtmlHelper:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;

public static class HtmlHelperExtensions
{
    public static MvcHtmlString DisplayNameFor<TModel, TEnumerable, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, IEnumerable<TEnumerable>>> enumerableExpression, Expression<Func<TEnumerable, TValue>> valueExpression)
    {
        var metadata = ModelMetadata.FromLambdaExpression(valueExpression, new ViewDataDictionary<TEnumerable>());
        string displayName = metadata.DisplayName ?? metadata.PropertyName ?? ExpressionHelper.GetExpressionText(valueExpression).Split('.').Last();
        return new MvcHtmlString(HttpUtility.HtmlEncode(displayName));
    }
}

And that's how it could be used in a view:

@Html.DisplayNameFor(m => m.Carriers, c => c.Name)
查看更多
对你真心纯属浪费
6楼-- · 2019-03-17 21:01

I've got a similar problem, because i don't want to type my column names by hand so i wrote a helper:

public static IHtmlString DisplayColumnNameFor<TModel, TClass, TProperty>
    (this HtmlHelper<TModel> helper, IEnumerable<TClass> model,
    Expression<Func<TClass, TProperty>> expression)
{ 
    var name = ExpressionHelper.GetExpressionText(expression);
    name = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
    var metadata = ModelMetadataProviders.Current.GetMetadataForProperty(
        () => Activator.CreateInstance<TClass>(), typeof(TClass), name);

    return new MvcHtmlString(metadata.DisplayName);
}

Then in the view you'll call it

@Html.DisplayColumnNameFor(Model.Carriers, m => m.Name)

Please note that you can use Display attribute which accepts Name and many other customization like Resource file etc.

public class Carrier
{
  [Display(Name="Carrier ID")]
  public Guid CarrierId { get; set; }
  [Display(Name="Carrier Name")]
  public string Name { get; set; }
}
查看更多
登录 后发表回答