Creo que esto es bastante simple, simplemente parece que no puedo encontrar la manera correcta de mostrar el nombre para mostrar de un elemento dentro de una lista dentro de mi modelo.
Mi 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; } }
}
y nombres:
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; }
}
Ahora me gustaría hacer una tabla para mostrar todos los nombres de una persona y obtener DisplayNameFor FullName. Obviamente,
@Html.DisplayNameFor(model => model.Names.FullName);
no funcionaría, y
@Html.DisplayNameFor(model => model.Names[0].FullName);
se romperá si no hay nombres. ¿Existe una "mejor manera" de obtener el nombre para mostrar aquí?
fuente
List<PersonNameViewModel>
tiene unIEnumerable<PersonNameViewModel>
, entonces también es seguro usar la expresiónmodel => model.Names.First().FullName
. ¿Es esto correcto? Dicho esto, creo que me gusta eldummyModel
mejor ejemplo de los tres. De lo contrario, podría tener varias propiedades en las que deba escribir o pegarmodel.Names[0].
. Por otra parte, tal vez debería refactorizar la sección a una vista parcial que acepteList
oIEnumerable
como modelo.FirstOrDefault()
funciona con una lista vacía.Hay otra forma de hacerlo, y supongo que es más 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(); } } }
Y luego, en la vista:
@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>
fuente
Me gusta la solución de T-moty. Necesitaba una solución con genéricos, por lo que mi solución es esencialmente 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 esto en la vista es lo mismo que en su ejemplo. Creo una única instancia de un objeto vacío, por lo que no creo una nueva instancia cada vez que hago referencia a Default .
Tenga en cuenta que la restricción new () es necesaria para llamar a new T () . Si su clase de modelo no tiene un constructor predeterminado, o necesita agregar argumentos al constructor, puede usar esto:
private T defaultInstance = (T)Activator.CreateInstance(typeof(T), new object[] { "args" });
La vista tendrá una línea @model como:
fuente
DisplayNameFor
realidad nunca llamaget
a la propiedad, por lo que no importa si crea una instancia.Como solución alternativa, puede probar:
¡Funcionará incluso si la lista está vacía!
fuente