2012-10-19 8 views
7

Ho una proprietà che è un IEnumerableCreazione HiddenFor IEnumerable <String> in vista

public IEnumerable<string> ChangesOthersResult { get; set; } 

ho bisogno di raccogliere tutti i valori da ChangesOthersResult e post da una vista al controller. Come posso scorrere l'Ienumerable e creare campi nascosti che si collegheranno a ViewModel nel controller?

foreach(var item in Model.ChangesOthersResult) 
    { 
     @Html.HiddenFor(x => x.ChangesOthersResult); 
    } 

Mi sta dando l'istruzione SQL Raw come testo.

risposta

11

Converti ChangesOthersResult ad un array e utilizzare un ciclo for per l'uscita qualcosa In questo modo:

for (int i = 0; i < Model.ChangesOthersResult.Length; i++)  
{ 
    @Html.Hidden("ChangesOthersResult[" + i + "]", Model.ChangesOthersResult[i]) 
} 
+0

Nota, non è necessario convertire in un array, questo è solo un modo per farlo. –

+0

Per completezza puoi aggiungere il codice da convertire in un array - grazie. – niico

2

nel costruttore del modello, nuovo l'IEnumerable ChagesOthersResult

public Model() 
{ 
    ChangesOthersResult = new List<string>(); 
} 

Poi nella vista, utilizzare un ciclo for

for(int i = 0; i < Model.ChangesOthersResult.Count; i++) 
{ 
    @Html.HiddenFor(x => x.ChangesOthersResult[i]) 
} 
+0

Il promemoria per inizializzare la raccolta all'interno del costruttore senza parametri è un componente critico mancante da altre risposte – OneManBand

18

Ho fatto questo in un metodo di estensione in modo che il per ciclo non uglify il codice di vista:

public static class HiddenExtensions 
{ 
    public static MvcHtmlString HiddenForEnumerable<TModel, TProperty>(this HtmlHelper<TModel> helper, 
     Expression<Func<TModel, IEnumerable<TProperty>>> expression) 

    { 
     var sb = new StringBuilder(); 

     var membername = expression.GetMemberName(); 
     var model = helper.ViewData.Model; 
     var list = expression.Compile()(model); 

     for (var i = 0; i < list.Count(); i++) 
     { 
      sb.Append(helper.Hidden(string.Format("{0}[{1}]", membername, i), list.ElementAt(i))); 
     } 

     return new MvcHtmlString(sb.ToString()); 
    } 
} 

GetMemberName è un altro metodo di estensione:

public static string GetMemberName<TModel, T>(this Expression<Func<TModel, T>> input) 
    { 
     if (input == null) 
      return null; 

     if (input.Body.NodeType != ExpressionType.MemberAccess) 
      return null; 

     var memberExp = input.Body as MemberExpression; 
     return memberExp != null ? memberExp.Member.Name : null; 
    } 

Spero che questo è utile.

+1

Questo è il modo più gestibile. Non gettare loop nel tuo codice che devi riscrivere ogni volta che vuoi usarlo. – Matthew

+0

Voto positivo per l'invenzione della parola uglify. Genio puro. – Sentinel

+0

Dove esattamente andrebbe questa lezione? – socketman

3

non può utilizzare. ForEach(), poiché @ Html.HiddenFor (x => x.ChangesOthersResult) creerà lo stesso ID elemento, che il modello non riconoscerà nel postback.

for (int i = 0; i < Model.ChangesOthersResult.Count(); i++)  
{ 
    @Html.HiddenFor(x => x.ChangesOthersResult[I]); 
} 
5

esteso soluzione @GitteTitter s' per gli elenchi di oggetti personalizzati:

@Html.HiddenForEnumerable(x => x.ValueTypes)  
@Html.HiddenForEnumerable(x => x.ViewModels, h=>h.Id, h=>h.Name) 
@Html.HiddenForEnumerable(x => x.ViewModels, allPublicProps: true) 

Fonte:

/// <summary> 
/// Returns hiddens for every IEnumerable item, with it's selected properties, if any memberPropsExpression provided. 
/// </summary> 
public static MvcHtmlString HiddenForEnumerable<TModel, TModelProperty>(this HtmlHelper<TModel> helper, 
    Expression<Func<TModel, IEnumerable<TModelProperty>>> expression, params Expression<Func<TModelProperty, object>>[] memberPropsExpressions) 
{ 
    var sb = new StringBuilder(); 

    var membername = expression.GetMemberName(); 
    var model = helper.ViewData.Model; 
    var list = expression.Compile()(model); 

    var memPropsInfo = memberPropsExpressions.Select(x => new 
    { 
     MemberPropName = x.GetMemberName(), 
     ListItemPropGetter = x.Compile() 
    }).ToList(); 

    for (var i = 0; i < list.Count(); i++) 
    { 
     var listItem = list.ElementAt(i); 
     if (memPropsInfo.Any()) 
     { 
      foreach (var q in memPropsInfo) 
      { 
       sb.Append(helper.Hidden(string.Format("{0}[{1}].{2}", membername, i, q.MemberPropName), q.ListItemPropGetter(listItem))); 
      } 
     } 
     else 
     { 
      sb.Append(helper.Hidden(string.Format("{0}[{1}]", membername, i), listItem)); 
     } 
    } 

    return new MvcHtmlString(sb.ToString()); 
} 

/// <summary> 
/// Returns hiddens for every IEnumerable item, with it's all public writable properties, if allPublicProps set to true. 
/// </summary> 
public static MvcHtmlString HiddenForEnumerable<TModel, TModelProperty>(this HtmlHelper<TModel> helper, 
    Expression<Func<TModel, IEnumerable<TModelProperty>>> expression, bool allPublicProps) 
{ 
    if (!allPublicProps) 
     return HiddenForEnumerable(helper, expression); 

    var sb = new StringBuilder(); 

    var membername = expression.GetMemberName(); 
    var model = helper.ViewData.Model; 
    var list = expression.Compile()(model); 

    var type = typeof(TModelProperty); 
    var memPropsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) 
     .Where(x => x.GetSetMethod(false) != null && x.GetGetMethod(false) != null) 
     .Select(x => new 
     { 
      MemberPropName = x.Name, 
      ListItemPropGetter = (Func<TModelProperty, object>)(p => x.GetValue(p, null)) 
     }).ToList(); 

    if (memPropsInfo.Count == 0) 
     return HiddenForEnumerable(helper, expression); 

    for (var i = 0; i < list.Count(); i++) 
    { 
     var listItem = list.ElementAt(i); 
     foreach (var q in memPropsInfo) 
     { 
      sb.Append(helper.Hidden(string.Format("{0}[{1}].{2}", membername, i, q.MemberPropName), q.ListItemPropGetter(listItem))); 
     } 
    } 

    return new MvcHtmlString(sb.ToString()); 
} 

public static string GetMemberName<TModel, T>(this Expression<Func<TModel, T>> input) 
{ 
    if (input == null) 
     return null; 

    MemberExpression memberExp = null; 

    if (input.Body.NodeType == ExpressionType.MemberAccess) 
     memberExp = input.Body as MemberExpression; 
    else if (input.Body.NodeType == ExpressionType.Convert) 
     memberExp = ((UnaryExpression)input.Body).Operand as MemberExpression; 

    return memberExp != null ? memberExp.Member.Name : null; 
} 
+0

Ho avuto un'altra idea per un'estensione che voglio costruire sopra, ma sto lottando un po 'con. Il mio obiettivo è creare qualcosa come @ Html.HiddenForClass (m => m.SomePOCO) che crea campi nascosti per tutte le proprietà su una determinata classe. Posso preparare il frammento su cui sto lavorando? È troppo grande da incollare qui ... –

+0

Meglio creare una nuova domanda per questo – smg

2

Come su un approccio ricorsivo?

public static MvcHtmlString HiddenForEnumerable<TModel, TModelProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, IEnumerable<TModelProperty>>> expression, string prefix = null) 
{ 
    var sb = new StringBuilder(); 

    var membername = expression.GetMemberName(); 
    var model = htmlHelper.ViewData.Model; 
    var list = expression.Compile()(model); 

    var type = typeof(TModelProperty); 
    var memPropertyInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) 
     .Where(x => x.GetSetMethod(false) != null && x.GetGetMethod(false) != null) 
     .Select(x => new 
     { 
      Type = x.PropertyType, 
      x.Name, 
      Get = (Func<TModelProperty, object>)(p => x.GetValue(p, null)) 
     }).ToList(); 

    for (var i = 0; i < list.Count(); i++) 
    { 
     var listItem = list.ElementAt(i); 
     if (memPropertyInfo.Any()) 
     { 
      foreach (var m in memPropertyInfo) 
      { 
       var inputName = $"{prefix ?? ""}{membername}[{i}].{m.Name}"; 
       var inputValue = m.Get(listItem); 
       var genericArguments = m.Type.GetGenericArguments(); 

       if (genericArguments.Any() && IsEnumerableType(m.Type)) 
       { 
        var delegateType = typeof(Func<,>).MakeGenericType(typeof(TModel), m.Type); 
        var bodyExpression = Expression.Constant(inputValue, m.Type); 
        var paramExpression = Expression.Parameter(typeof(TModel), "model"); 
        var expressionTree = Expression.Lambda(delegateType, bodyExpression, new[] { paramExpression }); 
        var hiddenForEnumerableInfo = typeof(HtmlHelpers).GetMethod("HiddenForEnumerable"); 
        var hiddenForEnumerable = hiddenForEnumerableInfo.MakeGenericMethod(typeof(TModel), genericArguments[0]); 
        object[] args = { htmlHelper, expressionTree, inputName }; 

        sb.Append(hiddenForEnumerable.Invoke(null, args)); 
       } 
       else 
       { 
        sb.Append(htmlHelper.Hidden(inputName, inputValue)); 
       } 
      } 
     } 
     else 
     { 
      sb.Append(htmlHelper.Hidden($"{membername}[{i}]", listItem)); 
     } 
    } 

    return new MvcHtmlString(sb.ToString()); 
} 

private static string GetMemberName<TModel, T>(this Expression<Func<TModel, T>> input) 
{ 
    if (input == null) 
     return null; 

    MemberExpression memberExp = null; 

    if (input.Body.NodeType == ExpressionType.MemberAccess) 
     memberExp = input.Body as MemberExpression; 
    else if (input.Body.NodeType == ExpressionType.Convert) 
     memberExp = ((UnaryExpression)input.Body).Operand as MemberExpression; 

    return memberExp?.Member.Name; 
} 

private static bool IsEnumerableType(Type type) 
{ 
    return (type.GetInterface("IEnumerable") != null); 
} 

Esempio:

public class Model 
{ 
    IEnumerable<Order> Orders { get; set; } 
} 

public class Order 
{ 
    public int OrderId { get; set; } 
    IEnumerable<Item> Items { get; set; } 
} 

public class Item 
{ 
    public int ItemId { get; set; } 
    public string Name { get; set; } 
} 

utilizzati:

@Html.HiddenForEnumerable(model => model.Orders) 

uscita:

<input id="Orders_0__OrderId" name="Orders[0].OrderId" type="hidden" value="1001"> 
<input id="Orders_0__Items_0__ItemId" name="Orders[0].Items[0].ItemId" type="hidden" value="201"> 
<input id="Orders_0__Items_0__Name" name="Orders[0].Items[0].Name" type="hidden" value="Something1"> 
<input id="Orders_0__Items_1__ItemId" name="Orders[0].Items[1].ItemId" type="hidden" value="202"> 
<input id="Orders_0__Items_1__Name" name="Orders[0].Items[1].Name" type="hidden" value="Something2"> 
<input id="Orders_1__OrderId" name="Orders[1].OrderId" type="hidden" value="1002"> 
<input id="Orders_1__Items_0__ItemId" name="Orders[1].Items[0].ItemId" type="hidden" value="205"> 
<input id="Orders_1__Items_0__Name" name="Orders[1].Items[0].Name" type="hidden" value="Something5"> 
0

lo stesso per aspnetcore

using Microsoft.AspNetCore.Html; 
using Microsoft.AspNetCore.Mvc.Rendering; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Reflection; 
using System.Text; 

namespace Proj.Helpers 
{ 
    public static class HtmlHelpers 
    { 
     public static IHtmlContent HiddenForEnumerable<TModel, TModelProperty>(this IHtmlHelper<TModel> helper, 
    Expression<Func<TModel, IEnumerable<TModelProperty>>> expression, params Expression<Func<TModelProperty, object>>[] memberPropsExpressions) 
     { 
      var hcb = new HtmlContentBuilder(); 

      var membername = expression.GetMemberName(); 
      var model = helper.ViewData.Model; 
      var list = expression.Compile()(model); 

      var memPropsInfo = memberPropsExpressions.Select(x => new 
      { 
       MemberPropName = x.GetMemberName(), 
       ListItemPropGetter = x.Compile() 
      }).ToList(); 

      for (var i = 0; i < list.Count(); i++) 
      { 
       var listItem = list.ElementAt(i); 
       if (memPropsInfo.Any()) 
       { 
        foreach (var q in memPropsInfo) 
        { 
         hcb.AppendHtml(helper.Hidden(string.Format("{0}[{1}].{2}", membername, i, q.MemberPropName), q.ListItemPropGetter(listItem))); 
        } 
       } 
       else 
       { 
        hcb.AppendHtml(helper.Hidden(string.Format("{0}[{1}]", membername, i), listItem)); 
       } 
      } 

      return hcb; 
     } 

     /// <summary> 
     /// Returns hiddens for every IEnumerable item, with it's all public writable properties, if allPublicProps set to true. 
     /// </summary> 
     public static IHtmlContent HiddenForEnumerable<TModel, TModelProperty>(this IHtmlHelper<TModel> helper, 
      Expression<Func<TModel, IEnumerable<TModelProperty>>> expression, bool allPublicProps) 
     { 
      if (!allPublicProps) 
       return HiddenForEnumerable(helper, expression); 

      var hcb = new HtmlContentBuilder(); 

      var membername = expression.GetMemberName(); 
      var model = helper.ViewData.Model; 
      var list = expression.Compile()(model); 

      var type = typeof(TModelProperty); 
      var memPropsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) 
       .Where(x => x.GetSetMethod(false) != null && x.GetGetMethod(false) != null) 
       .Select(x => new 
       { 
        MemberPropName = x.Name, 
        ListItemPropGetter = (Func<TModelProperty, object>)(p => x.GetValue(p, null)) 
       }).ToList(); 

      if (memPropsInfo.Count == 0) 
       return HiddenForEnumerable(helper, expression); 

      for (var i = 0; i < list.Count(); i++) 
      { 
       var listItem = list.ElementAt(i); 
       foreach (var q in memPropsInfo) 
       { 
        hcb.AppendHtml(helper.Hidden(string.Format("{0}[{1}].{2}", membername, i, q.MemberPropName), q.ListItemPropGetter(listItem))); 
       } 
      } 

      return hcb; 
     } 

     public static string GetMemberName<TModel, T>(this Expression<Func<TModel, T>> input) 
     { 
      if (input == null) 
       return null; 

      MemberExpression memberExp = null; 

      if (input.Body.NodeType == ExpressionType.MemberAccess) 
       memberExp = input.Body as MemberExpression; 
      else if (input.Body.NodeType == ExpressionType.Convert) 
       memberExp = ((UnaryExpression)input.Body).Operand as MemberExpression; 

      return memberExp != null ? memberExp.Member.Name : null; 
     } 
    } 
} 
Problemi correlati