Looping through view Model properties in a View

2019-01-21 06:39发布

问题:

I have a painfully simple view model

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

And then the corresponding inputs on my view, but I'm wondering if there is a better way (such as a loop) to write similar TextBoxes to my view:

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

回答1:

You should access

ViewData.ModelMetadata.Properties. No reason to double the reflection effort, plus it figures out DataAttributes metadata for you.

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


回答2:

You should consider using an array.

However, if you wanted to go with reflection, it would look like this:

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


回答3:

Unless i'm missing something, I don't know why no-one has suggested this. Why is everyone looping and/or using reflection??

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

View:

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

EditorTemplates\EmailViewModel.cshtml

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

Loops are NEVER required in MVC. I repeat. NEVER



回答4:

This is the accepted way to do it

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:

You can use Reflection to loop through each property of your model...as below

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
}

Hope this helps...



回答6:

you could use reflection over the properties, or a simple for loop to generate the same HTML as is generated in your solution, but what's your goal?
For simplicity, what you have wins.

Reflection

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

Loop

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"/>
}


回答7:

Perhaps like this?

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])
 }
}