【问题标题】:Looping through view Model properties in a View循环浏览视图中的模型属性
【发布时间】:2012-03-28 22:57:40
【问题描述】:

我有一个非常简单的视图模型

public class TellAFriendViewModel
{
    public string Email1 { get; set; }
    public string Email2 { get; set; }
    public string Email3 { get; set; }
    public string Email4 { get; set; }
    public string Email5 { get; set; }
}

然后是我视图上的相应输入,但我想知道是否有更好的方法(例如循环)将类似的文本框写入我的视图:

@using (Html.BeginForm()){
    @Html.AntiForgeryToken()

    @Html.TextBoxFor(vm => vm.Email1)
    @Html.TextBoxFor(vm => vm.Email2)
    @Html.TextBoxFor(vm => vm.Email3)
    @Html.TextBoxFor(vm => vm.Email4)
    @Html.TextBoxFor(vm => vm.Email5)
}

【问题讨论】:

  • 您还可以考虑将您的输入压缩为一组电子邮件地址并在客户端上动态扩展或循环到剃刀代码中的预设迭代。 public string[] Emails ...

标签: c# .net asp.net-mvc-3


【解决方案1】:

你应该访问

ViewData.ModelMetadata.Properties。没有理由将反射工作加倍,而且它会为您计算 DataAttributes 元数据。

@foreach(var property in ViewData.ModelMetadata.Properties)
{
    <div class="editor-line">
        <label>@(property.DisplayName??property.PropertyName)</label>
        @Html.Editor(property.PropertyName)
    </div>
}

【讨论】:

  • 我在这里有一个问题,使用 foreach propertyinfo 或手动使用(与问题代码相同)单个属性有什么方便?如果 foreach 循环比我怀疑它可能会增加执行/过程的成本。
  • 2 个问题:有没有办法确定属性的顺序?那两个问号是什么property.DisplayName??property.PropertyName
  • 找到了我第二个问题的答案stackoverflow.com/questions/446835/…
  • @Sag1v ?? 在 C# 中称为 null coalescing operator。基本上我们说的是“如果property.DisplayName 不为空,则在此处发出;如果为空,则发出property.PropertyName”。我没有尝试过,所以我不知道它是否会起作用,但你也许可以使用DisplayAttribute.Order 属性。见msdn.microsoft.com/en-us/library/…
  • @Sag1v 如果属性尚未在ViewData.ModelMetadata.Properties 集合中预先排序,您可以随时尝试自己重新排序集合。也许只使用 LINQ OrderBy 扩展:@foreach(var property in ViewData.ModelMetadata.Properties.OrderBy(m =&gt; m.Order))...
【解决方案2】:

您应该考虑使用数组。

但是,如果你想使用反射,它看起来像这样:

@foreach (var prop in Model.GetType().GetProperties())
{
    @(Html.TextBox(prop.Name, prop.GetValue(Model, null)))
}

【讨论】:

  • PropertyInfo.GetValue 的语法不正确。 Model.GetType 在 Razor 中不起作用吗?如果是这样,那么它通常是首选。
  • 你是对的。 (之前的语法确实适用于 .NET 4.5,因为引入了 GetValue 的新重载)
  • 真的!?我刚刚开始在 4.5 中进行修补,主要是使用遗留 4 代码,所以很高兴知道我可以在扩展方法发布后删除它。
  • 是的,here it is :)
  • +1 - 虽然显然有更好的方法来解决这个问题。
【解决方案3】:

除非我遗漏了什么,否则我不知道为什么没有人建议这样做。为什么每个人都在循环和/或使用反射?

public class TellAFriendViewModel
{
    public ICollection<EmailViewModel> Emails { get; set; } // populate 5 of them in ctor or controller
}

public class EmailViewModel
{
    public string Email { get; set; }
}

查看:

@using (Html.BeginForm()){
    @Html.AntiForgeryToken()
    @Html.EditorFor(model => model.Emails)
}

EditorTemplates\EmailViewModel.cshtml

@Html.TextBoxFor(model => model.Email)

在 MVC 中从不需要循环。我重复。从不

【讨论】:

  • MVC 中从不需要循环。我重复。从来没有 - 不是这样。
  • @DavidB - 我坚持我的声明。在需要的地方举个例子,我会告诉你如何避免它。
  • 非常感谢您的回复,这是否包括没有 for 循环的助手?我会尝试提出一个挑战,因为我认为这是一个非常有争议的声明,没有任何理由。我确实喜欢被证明是错误的,所以我有时间会尝试发布一个示例
  • +1 我能找到支持ICollection&lt;&gt;的唯一例子。此外,“只有西斯的绝对交易”(hyuck :P)
  • @MattBaker 如果您被 MVC3 困住(根据这个问题),那么挑战可能是使用 EditorFor 在页面上获得一大组编辑框 - MVC3 中存在一个错误缓存部分视图模板,这意味着随着 EditorFor 调用次数的增加,性能会呈指数下降 - 这意味着对于 1000 个编辑器,将其换成手写输入循环是非常值得的。
【解决方案4】:

这是公认的方法

foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => !pm.HideSurroundingHtml && pm.ShowForEdit && !ViewData.TemplateInfo.Visited(pm))) {

<div class="form-group">

    <label>
        @prop.GetDisplayName() 
        @if (prop.IsRequired)
        {
            <span class="required">*</span>
        }
    </label>
    @Html.Editor(prop.PropertyName)

    @Html.ValidationMessage(prop.PropertyName, new {@class = "help-block"})
</div>

}

【讨论】:

    【解决方案5】:

    您可以使用反射循环遍历模型的每个属性...如下所示

    Type type = Model.GetType(); // Model is the object you are binding with in your view
    PropertyInfo[] properties = type.GetProperties();
    foreach (var property in properties)
    {
        // Code to create your text box for the property
    }
    

    希望这会有所帮助...

    【讨论】:

    • 此语法不适用于 Razor(或真正的 any)视图。
    【解决方案6】:

    可以对属性使用反射,或者使用简单的 for 循环来生成与您的解决方案中生成的 HTML 相同的 HTML,但您的目标是什么?
    为简单起见,您所拥有的就是胜利。

    反思

     foreach (var prop in typeof(whatever).GetProperties(BindingFlags.Instance | BindingFlags.Public))
     {
        @Html.TextBox(prop.Name, prop.GetValue(Model));
     }
    

    循环

    var numberProperties = 5; // you could also do typeof(whatever).GetProperties(BindingFlags.Instance | BindingFlags.Public).Count();
    @for(var i = 0; i < numberProperties; i++){
     <input type="text" name="Email@i" id="Email@i"/>
    }
    

    【讨论】:

    • 我只是好奇如何循环遍历模型来显示它们。在这种情况下,我可能会坚持提供的内容,但假设我有 90 封电子邮件输入,我可能不想写它们。
    • @NickBrown 如果您有 90 封电子邮件,并且您正在使设计永久化,您可能需要咨询某人来帮助您修复它,或者只是从阵列设计开始。
    【解决方案7】:

    大概是这样的?

    public class TellAFriendViewModel
    {
     List<string> Emails { get; set; }
    
     public TellAFriendViewModel()
     {
      Emails = new List<string>(5);
     }
    }
    
    @using (Html.BeginForm()){
     @Html.AntiForgeryToken()
    
     @for(int count = 0 ; count < model.Emails.Count; count++)
     {
      @Html.TextBoxFor(vm => vm.Emails[count])
     }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多