DisplayNameFor () зі списку <Object> у моделі


87

Я вважаю, що це досить просто, я просто не можу знайти правильний спосіб відобразити відображуване ім'я для елемента в списку в рамках своєї моделі.

Моя спрощена модель:

public class PersonViewModel
{
    public long ID { get; set; }

    private List<PersonNameViewModel> names = new List<PersonNameViewModel>();

    [Display(Name = "Names")]
    public List<PersonNameViewModel> Names { get { return names; } set { names = value; } }      
}

та імена:

public class PersonNameViewModel
{
    public long ID { get; set; }

    [Display(Name = "Set Primary")]
    public bool IsPrimary { get; set; }

    [Display(Name = "Full Name")]
    public string FullName { get; set; }
}

Тепер я хотів би скласти таблицю, щоб показати всі імена людини, і отримати DisplayNameFor FullName. Очевидно,

@Html.DisplayNameFor(model => model.Names.FullName);

не буде працювати, і

@Html.DisplayNameFor(model => model.Names[0].FullName);  

зламається, якщо немає імен. Чи існує тут «найкращий спосіб» отримати відображуване ім’я?

Відповіді:


143

Це насправді працює навіть без елементів у списку:

@Html.DisplayNameFor(model => model.Names[0].FullName)

Це працює, оскільки MVC аналізує вираз замість того, щоб насправді його виконати. Це дозволяє йому знайти потрібну властивість та атрибут, не потребуючи наявності елемента у списку.

Варто зазначити, що параметр ( modelвище) навіть не потрібно використовувати. Це теж працює:

@Html.DisplayNameFor(dummy => Model.Names[0].FullName)

Як і це:

@{ Namespace.Of.PersonNameViewModel dummyModel = null; }
@Html.DisplayNameFor(dummyParam => dummyModel.FullName)

Я припускаю, що якщо замість List<PersonNameViewModel>вас у вас є IEnumerable<PersonNameViewModel>, тоді також безпечно використовувати вираз model => model.Names.First().FullName. Це правильно? Тим не менш, я думаю, що мені найбільше подобається dummyModelприклад із трьох. В іншому випадку ви можете мати кілька властивостей, де вам потрібно ввести або вставити model.Names[0].. Знову ж, можливо, вам слід переформатувати розділ у частковий вигляд, який приймає Listабо IEnumerableяк свою модель.
aaaantoine

6
Я протестував і FirstOrDefault()працює з порожнім списком.
Джош К

На жаль, це не працює для IEnumerable майна.
Віллі Девід-молодший

7

Існує інший спосіб зробити це, і, мабуть, це більш зрозуміло:

public class Model
{
    [Display(Name = "Some Name for A")]
    public int PropA { get; set; }

    [Display(Name = "Some Name for B")]
    public string PropB { get; set; }
}

public class ModelCollection
{
    public List<Model> Models { get; set; }

    public Model Default
    {
        get { return new Model(); }
    }
}

А потім, у поданні:

@model ModelCollection

<div class="list">
    @foreach (var m in Model.Models)
    {
        <div class="item">
            @Html.DisplayNameFor(model => model.Default.PropA): @m.PropA
            <br />
            @Html.DisplayNameFor(model => model.Default.PropB): @m.PropB
        </div>
    }
</div>

1

Мені подобається рішення T-moty. Мені потрібне було рішення із використанням загальних препаратів, тому моє рішення полягає в наступному:

public class CustomList<T> : List<T> where T : new()
{       
    public static async Task<CustomList<T>> CreateAsync(IQueryable<T> source)
    {           
        return new CustomList<T>(List<T> list); //do whatever you need in the contructor, constructor omitted
    }

    private T defaultInstance = new T();

    public T Default
    {
        get { return defaultInstance; }
    }
}

Використання цього у поданні те саме, що і його приклад. Я створюю один екземпляр порожнього об'єкта, тому я не створюю новий екземпляр кожного разу, коли я посилаюся на Default .

Зверніть увагу, що обмеження new () потрібне для виклику нового T () . Якщо ваш клас моделі не має конструктора за замовчуванням, або вам потрібно додати аргументи до конструктора, ви можете використовувати це:

private T defaultInstance = (T)Activator.CreateInstance(typeof(T), new object[] { "args" });

У поданні буде рядок @model, наприклад:

@model CustomList<Namespace.Of.PersonNameViewModel.Model>

Зверніть увагу, що DisplayNameForнасправді ніколи не викликає getдля властивості, тому не має значення, чи створюєте ви екземпляр.
NetMage

1

Як альтернативне рішення ви можете спробувати:

@Html.DisplayNameFor(x => x.GetEnumerator().Current.ItemName)

Це спрацює, навіть якщо список порожній!


чому я повинен використовувати це рішення замість рішення Tim S?
EKanadily
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.