Uważam, że jest to całkiem proste, po prostu nie mogę znaleźć właściwego sposobu wyświetlania nazwy pozycji na liście w moim modelu.
Mój uproszczony model:
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; } }
}
i nazwy:
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; }
}
Teraz chciałbym utworzyć tabelę, aby pokazać wszystkie imiona i nazwiska osób, i pobrać DisplayNameFor FullName. Oczywiście,
@Html.DisplayNameFor(model => model.Names.FullName);
nie zadziała i
@Html.DisplayNameFor(model => model.Names[0].FullName);
pęknie, jeśli nie będzie nazw. Czy istnieje „najlepszy sposób” uzyskania tutaj nazwy wyświetlanej?
c#
asp.net-mvc
razor
model
Jonesopolis
źródło
źródło
List<PersonNameViewModel>
masz, to możeszIEnumerable<PersonNameViewModel>
również bezpiecznie użyć wyrażeniamodel => model.Names.First().FullName
. Czy to jest poprawne? To powiedziawszy, myślę, że najbardziej podoba mi siędummyModel
przykład z tych trzech. W przeciwnym razie możesz mieć kilka właściwości, w których musisz wpisać lub wkleićmodel.Names[0].
. Z drugiej strony, może powinieneś refaktoryzować przekrój do częściowego widoku, który akceptujeList
lubIEnumerable
jako model.FirstOrDefault()
działa z pustą listą.Jest na to inny sposób i wydaje mi się, że jest to bardziej przejrzyste:
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(); } } }
A potem w widoku:
@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>
źródło
Podoba mi się rozwiązanie T-moty. Potrzebowałem rozwiązania wykorzystującego typy generyczne, więc moje rozwiązanie jest zasadniczo takie:
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; } } }
Użycie tego w widoku jest tym samym, co jego przykład. Tworzę pojedyncze wystąpienie pustego obiektu, więc nie tworzę nowego wystąpienia za każdym razem, gdy odwołuję się do Default .
Uwaga, ograniczenie new () jest potrzebne do wywołania funkcji new T () . Jeśli twoja klasa modelu nie ma domyślnego konstruktora lub musisz dodać argumenty do konstruktora, możesz użyć tego:
private T defaultInstance = (T)Activator.CreateInstance(typeof(T), new object[] { "args" });
Widok będzie miał linię @model , taką jak:
źródło
DisplayNameFor
rzeczywistości nigdy nie wywołujeget
właściwości, więc nie ma znaczenia, czy utworzysz instancję.Jako alternatywne rozwiązanie możesz spróbować:
Będzie działać, nawet jeśli lista jest pusta!
źródło