Acredito que isso seja muito simples, mas não consigo encontrar a maneira certa de mostrar o nome de exibição de um item em uma lista dentro do meu modelo.
Meu modelo simplificado:
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; } }
}
e nomes:
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; }
}
Agora, gostaria de fazer uma tabela para mostrar todos os nomes de uma pessoa e obter o DisplayNameFor FullName. Obviamente,
@Html.DisplayNameFor(model => model.Names.FullName);
não funcionaria, e
@Html.DisplayNameFor(model => model.Names[0].FullName);
será interrompido se não houver nomes. Existe uma 'melhor maneira' de obter o nome de exibição aqui?
fonte
List<PersonNameViewModel>
você tiver umIEnumerable<PersonNameViewModel>
, também é seguro usar a expressãomodel => model.Names.First().FullName
. Isso está correto? Dito isso, acho que gosto dodummyModel
melhor exemplo dos três. Caso contrário, você pode ter várias propriedades nas quais precisa digitar ou colarmodel.Names[0].
. Então, novamente, talvez você deva refatorar a seção para uma visualização parcial que aceite oList
ouIEnumerable
como seu modelo.FirstOrDefault()
funciona com uma lista vazia.Há outra maneira de fazer isso, e acho que é mais clara:
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(); } } }
E então, na visualização:
@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>
fonte
Gosto da solução de T-moty. Eu precisava de uma solução usando genéricos, então minha solução é essencialmente esta:
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; } } }
Usar isso na visualização é o mesmo que seu exemplo. Eu crio uma única instância de um objeto vazio, então não estou criando uma nova instância toda vez que faço referência a Default .
Observe que a restrição new () é necessária para chamar new T () . Se sua classe de modelo não tem um construtor padrão, ou você precisa adicionar argumentos ao construtor, você pode usar isto:
private T defaultInstance = (T)Activator.CreateInstance(typeof(T), new object[] { "args" });
A visualização terá uma linha @model como:
fonte
DisplayNameFor
nunca realmente chama oget
for para a propriedade, portanto, não importa se você criar uma instância.Como solução alternativa, você pode tentar:
Funcionará mesmo se a lista estiver vazia!
fonte