2012-10-19 20 views
7

創建HiddenFor IEnumerable的 我有一個屬性是一個IEnumerable 在查看

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

我需要收集來自ChangesOthersResult和後所有值從視圖返回到控制器。我如何循環訪問Ienumerable並創建隱藏字段,這些隱藏字段將綁定回控制器中的ViewModel?

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

正在給我原始的SQL語句作爲文本。

回答

11

轉換ChangesOthersResult到一個數組,並使用for循環輸出的東西像這樣:

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

注缺少的重要組成部分,您不必轉換爲一個數組,這只是一個辦法做到這一點。 –

+0

爲了完整,您可以添加代碼以轉換爲數組 - 謝謝。 – niico

2

在模型的構造,新起來了IEnumerable ChagesOthersResult

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

然後在視圖中,使用一個for循環

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

你提醒初始化參數的構造函數內蒐集來自其他答案 – OneManBand

18

我把它做成了擴展方法,循環不醜化您的視圖代碼:

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是另一種擴展方法:

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

希望這是有幫助的。

+1

這是更可維護的方法。不要在您的代碼中引入循環,您每次需要重寫時都要使用它。 – Matthew

+0

Upvote單詞uglify的發明。純粹的天才。 – Sentinel

+0

這個班級去哪裏? – socketman

3

無法使用.ForEach(),因爲@ Html.HiddenFor(x => x.ChangesOthersResult)將創建相同的元素ID,該模型在回發時不會被識別。對於自定義對象的名單

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

擴展@GitteTitter的解決方案:

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

來源:

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

我有另一個想要擴展我想建立在此之上,但我掙扎了一下。我的目標是創建類似@ Html.HiddenForClass(m => m.SomePOCO)的東西,爲給定類的所有屬性創建隱藏字段。我可否在你正在處理的片段中填寫?它太大,不能粘貼在這裏... –

+0

更好地爲此創建新問題 – smg

2

如何遞歸的方法嗎?

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

實施例:

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

用法:

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

輸出:

<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

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