我已经在HtmlHelper上构建了一个CheckBoxListFor扩展,这要归功于这个精彩的答案http://bit.ly/Aevcea(下面的代码),但我发现它没有按预期发布。
我的表单基于一个模型组,该组具有(在其他属性中)字符串Name和int [] PersonIDs。
CheckBoxListFor呈现如下内容:
<ul>
<li><input type="checkbox" name="PersonIDs" value="1" id="PersonIDs_1" /></li>
<li><input type="checkbox" name="PersonIDs" value="2" id="PersonIDs_2" /></li>
</ul>
我的控制器有一个编辑(组组)方法来处理此表单的提交。但是,提交后我发现group.PersonIDs为null。虽然Request.Form [“PersonIDs”]设置为所选值(例如,如果检查上述两个项,则为“1,2”)。此外,如果我向我的Edit方法(int [] PersonIDs)添加另一个参数,那么它将带有预期内容(所选ID)。
有谁能解释我做错了什么?我的观点的相关位看起来像这样(额外的位被剥离):
@Html.TextBoxFor(m => m.Group.Name)
@Html.CheckBoxListFor(m => m.Group.PersonIDs, Model.MultiSelectListOfAllPeople)
请注意,我的Edit方法中的group参数确实返回了根据表单设置的名称。
为了完整起见,这是我的CheckBoxListFor扩展的完整主体:
public static MvcHtmlString CheckBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, IEnumerable<TProperty>>> expression, MultiSelectList multiSelectList, object htmlAttributes = null)
{
//Derive property name for checkbox name
MemberExpression body = expression.Body as MemberExpression;
string propertyName = body.Member.Name;
//Get currently select values from the ViewData model
IEnumerable<TProperty> list = expression.Compile().Invoke(htmlHelper.ViewData.Model);
//Convert selected value list to a List<string> for easy manipulation
List<string> selectedValues = new List<string>();
if (list != null)
{
selectedValues = new List<TProperty>(list).ConvertAll<string>(delegate(TProperty i) { return i.ToString(); });
}
//Create div
TagBuilder wrapper = new TagBuilder("ul");
wrapper.AddCssClass("clearfix");
wrapper.MergeAttributes(new RouteValueDictionary(htmlAttributes), true);
//Add checkboxes
foreach (SelectListItem item in multiSelectList)
{
wrapper.InnerHtml += String.Format("<li><input type=\"checkbox\" name=\"{0}\" id=\"{0}_{1}\" " +
"value=\"{1}\" {2} /><label for=\"{0}_{1}\">{3}</label></li>",
propertyName,
item.Value,
selectedValues.Contains(item.Value) ? "checked=\"checked\"" : "",
item.Text);
}
return MvcHtmlString.Create(wrapper.ToString());
}
答案 0 :(得分:1)
好的,问题是CheckBoxListFor扩展需要将控件名称呈现为Group.PersonID而不仅仅是PersonID。表单绑定到一个对象,该对象本身是视图模型的子属性。我已经快速调整了我的CheckBoxListFor方法,但是我会非常感激地接受更优雅的解决方案!我正在传递一个额外的布尔参数includeDeclaringType来告诉它是否在ID中包含声明类型的名称。不确定这是否可以通过任何其他方式推断..?
public static MvcHtmlString CheckBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, IEnumerable<TProperty>>> expression, MultiSelectList multiSelectList, bool includeDeclaringType, object htmlAttributes = null)
{
//Derive property name for checkbox name
MemberExpression body = expression.Body as MemberExpression;
string declaringTypeName = body.Member.DeclaringType.Name;
string propertyName = body.Member.Name;
//Get currently select values from the ViewData model
IEnumerable<TProperty> list = expression.Compile().Invoke(htmlHelper.ViewData.Model);
//Convert selected value list to a List<string> for easy manipulation
List<string> selectedValues = new List<string>();
if (list != null)
{
selectedValues = new List<TProperty>(list).ConvertAll<string>(delegate(TProperty i) { return i.ToString(); });
}
//Create div
TagBuilder wrapper = new TagBuilder("ul");
wrapper.AddCssClass("clearfix");
wrapper.MergeAttributes(new RouteValueDictionary(htmlAttributes), true);
//Add checkboxes
foreach (SelectListItem item in multiSelectList)
{
var name = string.Concat(
includeDeclaringType ? string.Format("{0}.", declaringTypeName) : "",
propertyName
);
var id = string.Concat(
includeDeclaringType ? string.Format("{0}_", declaringTypeName) : "",
propertyName,
"_",
item.Value
);
wrapper.InnerHtml += String.Format("<li><input type=\"checkbox\" name=\"{0}\" id=\"{1}\" " +
"value=\"{2}\" {3} /><label for=\"{1}\">{4}</label></li>",
name,
id,
item.Value,
selectedValues.Contains(item.Value) ? "checked=\"checked\"" : "",
item.Text);
}
return MvcHtmlString.Create(wrapper.ToString());
}
答案 1 :(得分:0)
您还可以使用ExpressionHelper.GetExpressionText方法,它会为您生成正确的输入名称:
var expressionText = ExpressionHelper.GetExpressionText(expression);
wrapper.InnerHtml +=
string.Format("<li><input type=\"checkbox\" name=\"{0}" id=\"{0}_{1}\" " +
"value=\"{1}\" {2} /><label for=\"{0}_{1}\">{3}</label></li>",
expressionText,
item.Value,
selectedValues.Contains(item.Value) ? "checked=\"checked\"" : "",
item.Text);