DisplayNameFor () From List <Object> in Model


88

Credo che sia piuttosto semplice, non riesco a trovare il modo giusto per mostrare il nome visualizzato per un elemento all'interno di un elenco all'interno del mio modello.

Il mio modello semplificato:

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 nomi:

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

Ora vorrei creare una tabella per mostrare tutti i nomi di una persona e ottenere DisplayNameFor FullName. Ovviamente,

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

non funzionerebbe, e

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

si romperà se non ci sono nomi. Esiste un "modo migliore" per ottenere il nome visualizzato qui?

Risposte:


144

Funziona effettivamente, anche senza elementi nell'elenco:

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

Funziona perché MVC analizza l'espressione invece di eseguirla effettivamente. Ciò consente di trovare la proprietà e l'attributo corretti senza che sia necessario un elemento nell'elenco.

Vale la pena notare che il parametro ( modelsopra) non ha nemmeno bisogno di essere utilizzato. Funziona anche questo:

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

Come fa questo:

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

Presumo che se invece di a List<PersonNameViewModel>hai un IEnumerable<PersonNameViewModel>, allora è anche sicuro usare l'espressione model => model.Names.First().FullName. È corretto? Detto questo, penso che mi piaccia l' dummyModelesempio migliore dei tre. Altrimenti, potresti avere diverse proprietà in cui devi digitare o incollare model.Names[0].. Poi di nuovo, forse dovresti rifattorizzare la sezione in una vista parziale che accetta Listo IEnumerablecome modello.
aaaantoine

6
Ho provato e FirstOrDefault()funziona con un elenco vuoto.
Josh K

Purtroppo questo non funziona sulla proprietà IEnumerable.
Willy David Jr

7

C'è un altro modo per farlo, e credo che sia più chiaro:

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 poi, nella 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>

3

Come soluzione alternativa potresti provare:

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

Funzionerà anche se l'elenco è vuoto!


perché dovrei usare questa soluzione invece della soluzione di Tim S?
EKanadily

1

Mi piace la soluzione di T-moty. Avevo bisogno di una soluzione che usasse i generici, quindi la mia soluzione è essenzialmente questa:

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

L'utilizzo di questo nella vista è lo stesso del suo esempio. Creo una singola istanza di un oggetto vuoto, quindi non creo una nuova istanza ogni volta che faccio riferimento a Default .

Nota, il vincolo new () è necessario per chiamare new T () . Se la tua classe modello non ha un costruttore predefinito, o devi aggiungere argomenti al costruttore, puoi usare questo:

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

La vista avrà una linea @model come:

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

Nota che DisplayNameFornon chiama mai effettivamente getla proprietà per la proprietà, quindi non importa se crei un'istanza.
NetMage
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.