DisplayNameFor()来自模型中的List <Object>


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

现在,我想制作一个表以显示一个人的所有名称,并获取DisplayNameFor FullName。明显,

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

不会工作,并且

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

如果没有名称,它将中断。是否有“最佳方法”在此处获取显示名称?

Answers:


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>有一个而不是一个IEnumerable<PersonNameViewModel>,那么使用表达式也是安全的model => model.Names.First().FullName。它是否正确?也就是说,我认为我dummyModel最喜欢这三个示例。否则,您可能需要在其中输入或粘贴几个属性model.Names[0].。再说一次,也许您应该将该部分重构为接受Listor或IEnumerable作为其模型的局部视图。
aaaantoine

6
我测试了并且FirstOrDefault()确实使用了一个空列表。
乔什(Josh K)

不幸的是,这对IEnumerable属性不起作用。
威利·大卫(Willy David Jr)

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

在视图中使用它与他的示例相同。我创建一个空对象的单个实例,所以我每次引用Default时都不会创建一个新实例。

注意,需要new()约束才能调用new T()。如果您的模型类没有默认构造函数,或者您需要向构造函数添加参数,则可以使用以下方法:

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.