@ Html.DisplayNameFor для получения подробной информации о модели

В моей модели у меня есть сущность

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

У меня также есть ViewModel

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

У меня есть строго типизированное (CarrierIndexViewModel) представление индекса, которое должно отображать таблицу Carrier с использованием PagingInfo.

Я пытаюсь использовать помощник Html для отображения Carrier.Name в заголовке моей таблицы. Когда я использовал IEnumerable в качестве модели для этого представления, у меня было @Html.DisplayFor(model => model.Name)

Как я могу получить тот же результат, используя мою новую модель CarrierIndexViewModel для отображения заголовка для Carrier.Name?


person Alex    schedule 21.02.2012    source источник


Ответы (5)


Вы можете добавить оператор @using к вашему View, чтобы указать тип Carrier, тогда вам нужно будет пройти через свойство Carriers вашей модели.

Ваш вид будет выглядеть примерно так ...

@model CarrierIndexViewModel
@using Carrier

@foreach(Carrier c in Model.Carriers)
{
 @Html.DisplayFor(model => c.Name)
}
person Jed    schedule 21.02.2012

Я обнаружил, что не нужны вспомогательные методы, дополнительный код или цикл по коллекции. Я просто использовал следующее:

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

Это по-прежнему работает, даже если FirstOrDefault() вернет null, потому что он ищет только метаданные, а само свойство Name недоступно.

Большое спасибо @Kurian, который вдохновил этот ответ.

person Red Taz    schedule 19.12.2013
comment
Спасибо. То, что я искал. Если Carrier - это список ‹›, вы можете использовать Carriers [0] или Carriers.FirstOrDefault (). - person Greg Little; 31.07.2014

У меня аналогичная проблема, потому что я не хочу набирать имена столбцов вручную, поэтому написал помощник:

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);
}

Тогда в представлении вы назовете это

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

Обратите внимание, что вы можете использовать атрибут Display, который принимает имя и многие другие настройки, такие как файл ресурсов и т. Д.

public class Carrier
{
  [Display(Name="Carrier ID")]
  public Guid CarrierId { get; set; }
  [Display(Name="Carrier Name")]
  public string Name { get; set; }
}
person Matija Grcic    schedule 23.03.2012
comment
Я еще не пробовал, но думаю, вы можете просто сказать m = ›m.Carriers [0] .Name. Поскольку он использует метаданные из лямбда-выражений внутри, не имеет значения, является ли Carriers нулевым или пустым. - person Monstieur; 28.03.2013
comment
Могу я предложить небольшую поправку? Если атрибут «Отображаемое имя» не был применен, вы захотите вернуть имя свойства следующим образом: return new MvcHtmlString (metadata.DisplayName ?? name) - person Darryl; 05.04.2013
comment
Мне нравится идея, лежащая в основе этого решения, но я чувствую, что слышу маленькие сигналы тревоги, когда я думаю об этом (возможно, мне не стоит об этом думать :)). Если я собирался потратить время на то, чтобы написать отображаемое значение для свойства в моем коде, почему бы просто не потратить время и не записать отображаемое значение в представлении? Похоже, что больше кода было написано только для предотвращения вставки значений в представление, хотя это действительно то, где оно должно быть в любом случае. - person jaryd; 06.12.2013
comment
@ phreak3eb Если вы хотите повысить ценность, сделайте это. Я использовал этот подход, чтобы локализовать [Display (Name = Some name)] и избежать жесткого кодирования. Здесь вы можете найти решение * .resx stackoverflow.com/a/20383378/1241400 - person Matija Grcic; 07.12.2013
comment
@plurby Хорошо, это гораздо лучший подход. Еще лучше поддерживает локализацию! :) - person jaryd; 09.12.2013
comment
Если TClass не имеет общедоступного конструктора без параметров, Activator.CreateInstance завершится ошибкой. Вместо этого используйте default(TClass). - person Aly Elhaddad; 25.04.2017

Вот подход, который основан на исходном DisplayNameFor методе расширения и работает согласованно.

Метод расширения для 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));
    }
}

И вот как это можно использовать в представлении:

@Html.DisplayNameFor(m => m.Carriers, c => c.Name)
person Deilan    schedule 16.04.2015

У меня было аналогичное требование, но мне нужно было получить отображаемые имена для свойств из другого неперечислимого класса, чтобы решение от @plurby не сработало. В итоге я решил эту проблему, создав беглый вызов, который можно использовать для получения нового HtmlHelper для любого произвольного типа. Код для расширения и адаптера:

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);
        }
    }
}

Затем вы можете использовать это в представлении следующим образом:

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

Одним из преимуществ является то, что этот подход будет работать для любого расширения HtmlHelper, а не только DisplayNameFor (но имейте в виду, что адаптированный HtmlHelper не имеет данных представления, поскольку все они набраны на основе модели, используемой в представлении, и, таким образом, выиграли '' t работать в адаптированном HtmlHelper).

person daveaglick    schedule 17.10.2012