DisplayNameFor () Dari Daftar <Object> di Model


88

Saya yakin ini cukup sederhana, saya sepertinya tidak dapat menemukan cara yang tepat untuk menampilkan nama tampilan item dalam daftar dalam model saya.

Model saya yang disederhanakan:

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

dan Nama:

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

Sekarang saya ingin membuat tabel untuk menampilkan semua nama seseorang, dan mendapatkan DisplayNameFor FullName. Jelas,

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

tidak akan berhasil, dan

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

akan rusak jika tidak ada nama. Adakah 'cara terbaik' untuk mendapatkan nama tampilan di sini?

Jawaban:


144

Ini benar-benar berfungsi, bahkan tanpa item dalam daftar:

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

Ini berfungsi karena MVC mengurai ekspresi alih-alih mengeksekusinya. Ini memungkinkannya menemukan properti dan atribut yang tepat tanpa perlu ada elemen dalam daftar.

Perlu dicatat bahwa parameter (di modelatas) bahkan tidak perlu digunakan. Ini juga berfungsi:

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

Seperti ini:

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

Saya berasumsi bahwa jika alih-alih List<PersonNameViewModel>Anda memiliki IEnumerable<PersonNameViewModel>, maka itu juga aman untuk menggunakan ekspresi model => model.Names.First().FullName. Apakah ini benar? Yang mengatakan, saya pikir saya paling suka dummyModelcontoh terbaik dari ketiganya. Jika tidak, Anda dapat memiliki beberapa properti yang perlu Anda ketik atau tempel model.Names[0].. Kemudian lagi, mungkin Anda harus mengubah bagian menjadi tampilan parsial yang menerima Listatau IEnumerablesebagai modelnya.
aaaantoine

6
Saya menguji dan FirstOrDefault()bekerja dengan daftar kosong.
Josh K

Sayangnya ini tidak berfungsi pada properti IEnumerable.
Willy David Jr

7

Ada cara lain untuk melakukannya, dan saya rasa itu lebih jelas:

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

Dan kemudian, dalam tampilan:

@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

Sebagai solusi alternatif, Anda dapat mencoba:

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

Ini akan berfungsi bahkan jika daftarnya kosong!


mengapa saya harus menggunakan solusi ini daripada solusi Tim S?
EKanadily

1

Saya suka solusi T-moty. Saya membutuhkan solusi menggunakan obat generik sehingga solusi saya pada dasarnya adalah ini:

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

Menggunakan ini dalam tampilan sama dengan contohnya. Saya membuat satu instance dari objek kosong jadi saya tidak membuat instance baru setiap kali saya mereferensikan Default .

Catatan, batasan new () diperlukan untuk memanggil T () baru . Jika kelas model Anda tidak memiliki kontraktor default, atau Anda perlu menambahkan argumen ke konstruktor, Anda dapat menggunakan ini:

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

Tampilan akan memiliki baris @model seperti:

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

Perhatikan bahwa DisplayNameFortidak pernah benar-benar memanggil getuntuk properti, jadi tidak masalah jika Anda membuat sebuah instance.
NetMage
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.