在View中创建HiddenFor IEnumerable
我有一个IEnumerable属性
public IEnumerable ChangesOthersResult { get; set; }
我需要从ChangesOthersResult收集所有值并从视图发回到控制器。 我如何遍历Ienumerable并创建将绑定回控制器中的ViewModel的隐藏字段?
foreach(var item in Model.ChangesOthersResult) { @Html.HiddenFor(x => x.ChangesOthersResult); }
给我Raw SQL语句作为文本。
将ChangesOthersResult转换为数组并使用for循环输出如下内容:
for (int i = 0; i < Model.ChangesOthersResult.Length; i++ ) { @Html.Hidden("ChangesOthersResult[" + i + "]", Model.ChangesOthersResult[i]) }
我把它变成了一个扩展方法,因此for循环不会使你的视图代码变得丑化:
public static class HiddenExtensions { public static MvcHtmlString HiddenForEnumerable(this HtmlHelper helper, Expression>> 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(this Expression> 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; }
希望这有用。
扩展@GitteTitter的自定义对象列表解决方案:
@Html.HiddenForEnumerable(x => x.ValueTypes) @Html.HiddenForEnumerable(x => x.ViewModels, h=>h.Id, h=>h.Name) @Html.HiddenForEnumerable(x => x.ViewModels, allPublicProps: true)
资源:
/// /// Returns hiddens for every IEnumerable item, with it's selected properties, if any memberPropsExpression provided. /// public static MvcHtmlString HiddenForEnumerable(this HtmlHelper helper, Expression>> expression, params Expression>[] 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()); } /// /// Returns hiddens for every IEnumerable item, with it's all public writable properties, if allPublicProps set to true. /// public static MvcHtmlString HiddenForEnumerable(this HtmlHelper helper, Expression>> 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)(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(this Expression> 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; }
不能使用.ForEach(),因为@ Html.HiddenFor(x => x.ChangesOthersResult)将创建相同的元素ID,模型在回发时将无法识别。
for (int i = 0; i < Model.ChangesOthersResult.Count(); i++ ) { @Html.HiddenFor(x => x.ChangesOthersResult[I]); }
递归方法怎么样?
public static MvcHtmlString HiddenForEnumerable(this HtmlHelper htmlHelper, Expression>> 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)(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(this Expression> 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 Orders { get; set; } } public class Order { public int OrderId { get; set; } IEnumerable- Items { get; set; } } public class Item { public int ItemId { get; set; } public string Name { get; set; } }
用法:
@Html.HiddenForEnumerable(model => model.Orders)
输出:
在你的模型的构造函数中,新建了IEnumerable ChagesOthersResult
public Model () { ChangesOthersResult = new List(); }
然后在视图中,使用for循环
for(int i = 0; i < Model.ChangesOthersResult.Count; i++) { @Html.HiddenFor(x => x.ChangesOthersResult[i]) }
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(this IHtmlHelper helper, Expression>> expression, params Expression>[] 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; } /// /// Returns hiddens for every IEnumerable item, with it's all public writable properties, if allPublicProps set to true. /// public static IHtmlContent HiddenForEnumerable(this IHtmlHelper helper, Expression>> 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)(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(this Expression> 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; } } }