モデルのList <Object>からのDisplayNameFor()


87

これは非常に簡単だと思います。モデル内のリスト内のアイテムの表示名を表示する正しい方法が見つからないようです。

私の簡略化されたモデル:

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

と名前:

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

ここで、人のすべての名前を表示するテーブルを作成し、DisplayNameForFullNameを取得したいと思います。明らかに、

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

動作しません、そして

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

名前がない場合は壊れます。ここで表示名を取得するための「最良の方法」はありますか?

回答:


143

これは、リストに項目がなくても実際に機能します。

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

これは、MVCが実際に式を実行するのではなく、式を解析するために機能します。これにより、リストに要素がなくても、適切なプロパティと属性を見つけることができます。

パラメータ(model上記)を使用する必要さえないことは注目に値します。これも機能します:

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

これがするように:

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

の代わりにがあれば、式を使用しても安全だとList<PersonNameViewModel>思います。これは正しいです?そうは言っても、私は3つの例の中で一番好きだと思います。それ以外の場合は、を入力または貼り付ける必要があるいくつかのプロパティがあります。次に、またはをモデルとして受け入れる部分ビューにセクションをリファクタリングする必要があるかもしれません。IEnumerable<PersonNameViewModel>model => model.Names.First().FullNamedummyModelmodel.Names[0].ListIEnumerable
aaaantoine 2016年

6
私はテストFirstOrDefault()し、空のリストで動作します。
Josh K

残念ながら、これはIEnumerableプロパティでは機能しません。
ウィリーデビッドジュニア

7

それを行う別の方法があります、そして私はそれがより明確だと思います:

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

そして、ビューで:

@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>

1

私はT-motyのソリューションが好きです。ジェネリックを使用したソリューションが必要だったので、私のソリューションは基本的に次のようになります。

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

ビューでこれを使用することは、彼の例と同じです。空のオブジェクトのインスタンスを1つ作成するので、Defaultを参照するたびに新しいインスタンスを作成するわけではありません。

new T()を呼び出すには、new()制約が必要であることに注意してください。モデルクラスにデフォルトのコンストラクターがない場合、またはコンストラクターに引数を追加する必要がある場合は、次のように使用できます。

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

ビューには、次のような@model行があります。

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

DisplayNameFor決して実際に呼び出してgetインスタンスを作成する場合、それは問題ではないので、プロパティのために。
NetMage

1

別の解決策として、次のことを試すことができます。

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

リストが空の場合でも機能します!


Tim Sのソリューションの代わりにこのソリューションを使用する必要があるのはなぜですか?
EKanadily
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.