DisplayNameFor () Aus Liste <Objekt> im Modell

86

Ich glaube, das ist ziemlich einfach. Ich kann einfach nicht den richtigen Weg finden, um den Anzeigenamen für ein Element in einer Liste in meinem Modell anzuzeigen.

Mein vereinfachtes Modell:

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

und Namen:

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

Jetzt möchte ich eine Tabelle erstellen, in der alle Namen einer Person angezeigt werden, und den Anzeigenamen für den vollständigen Namen erhalten. Offensichtlich,

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

würde nicht funktionieren, und

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

wird brechen, wenn es keine Namen gibt. Gibt es hier einen "besten Weg", um den Anzeigenamen zu erhalten?

Jonesopolis
quelle

Antworten:

142

Dies funktioniert auch ohne Elemente in der Liste:

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

Dies funktioniert, weil MVC den Ausdruck analysiert, anstatt ihn tatsächlich auszuführen. Auf diese Weise kann die richtige Eigenschaft und das richtige Attribut gefunden werden, ohne dass ein Element in der Liste vorhanden sein muss.

Es ist erwähnenswert, dass der Parameter ( modeloben) nicht einmal verwendet werden muss. Das funktioniert auch:

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

Wie das:

@{ Namespace.Of.PersonNameViewModel dummyModel = null; }
@Html.DisplayNameFor(dummyParam => dummyModel.FullName)
Tim S.
quelle
Ich gehe davon aus, dass es auch sicher ist, den Ausdruck zu verwenden , wenn Sie anstelle eines einen List<PersonNameViewModel>haben . Ist das richtig? Trotzdem denke ich, dass mir das Beispiel am besten gefällt . Andernfalls könnten Sie mehrere Eigenschaften haben, die Sie eingeben oder einfügen müssen . Andererseits sollten Sie den Abschnitt möglicherweise in eine Teilansicht umgestalten, die das oder als Modell akzeptiert . IEnumerable<PersonNameViewModel>model => model.Names.First().FullNamedummyModelmodel.Names[0].ListIEnumerable
aaaantoine
6
Ich habe getestet und FirstOrDefault()arbeite mit einer leeren Liste.
Josh K
Leider funktioniert dies bei IEnumerable-Eigenschaften nicht.
Willy David Jr
7

Es gibt noch einen anderen Weg, und ich denke, das ist klarer:

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

Und dann in der Ansicht:

@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>
T-Moty
quelle
1

Ich mag die Lösung von T-moty. Ich brauchte eine Lösung mit Generika, daher lautet meine Lösung im Wesentlichen:

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

Die Verwendung in der Ansicht entspricht seinem Beispiel. Ich erstelle eine einzelne Instanz eines leeren Objekts, damit ich nicht jedes Mal eine neue Instanz erstelle, wenn ich auf Standard verweise .

Beachten Sie, dass die Einschränkung new () benötigt wird, um new T () aufzurufen . Wenn Ihre Modellklasse keinen Standardkonstruktor hat oder Sie dem Konstruktor Argumente hinzufügen müssen, können Sie Folgendes verwenden:

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

Die Ansicht hat eine @ Modellzeile wie:

@model CustomList<Namespace.Of.PersonNameViewModel.Model>
shox
quelle
Beachten Sie, dass DisplayNameForniemals die getfor-Eigenschaft aufgerufen wird, sodass es keine Rolle spielt, ob Sie eine Instanz erstellen.
NetMage
0

Als alternative Lösung können Sie Folgendes versuchen:

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

Es wird auch funktionieren, wenn die Liste leer ist!

Fábio Fabian
quelle
Warum sollte ich diese Lösung anstelle der Lösung von Tim S verwenden?
EKanadily