我知道ASP.NET MVC Html助手扩展方法中有一个ListBoxFor
扩展方法,但我认为复选框列表比列表框更加用户友好。
在老旧的WebForms中,有一个非常方便的CheckBoxList
控件,但显然现在已经过时了。
问题是,为什么ASP.NET MVC没有创建复选框列表的方式?我该如何编写自己的扩展方法,以创建复选框列表并像ListBoxFor
一样运作?
我知道ASP.NET MVC Html助手扩展方法中有一个ListBoxFor
扩展方法,但我认为复选框列表比列表框更加用户友好。
在老旧的WebForms中,有一个非常方便的CheckBoxList
控件,但显然现在已经过时了。
问题是,为什么ASP.NET MVC没有创建复选框列表的方式?我该如何编写自己的扩展方法,以创建复选框列表并像ListBoxFor
一样运作?
这里提供了一个强类型的HtmlHelper,用于处理CheckBoxListFor,并将所选项目作为数组保存在您的viewdata模型中。我选择不包装Html.CheckBox或Html.CheckBoxFor方法,因为我不希望在我的复选框列表中出现隐藏的“false”字段。
请随意进行改进并重新发布 :-)
//View
<%: Html.CheckBoxListFor(model => model.FreightTypeIds, FreightTypeMultiSelectList) %>
//Controller
public ActionResult SomeAction(int[] FreightTypeIds)
{
//...
return View();
}
//Extension
public static MvcHtmlString CheckBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, IEnumerable<TProperty>>> expression, MultiSelectList allOptions, object htmlAttributes = null)
{
ModelMetadata modelMetadata = ModelMetadata.FromLambdaExpression<TModel, IEnumerable<TProperty>>(expression, htmlHelper.ViewData);
// Derive property name for checkbox name
string propertyName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(modelMetadata.PropertyName);
// 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
IList<string> selectedValues = new List<string>();
if (list != null)
{
selectedValues = new List<TProperty>(list).ConvertAll<string>(delegate(TProperty i) { return i.ToString(); });
}
// Create div
TagBuilder divTag = new TagBuilder("div");
divTag.MergeAttributes(new RouteValueDictionary(htmlAttributes), true);
// Add checkboxes
foreach (SelectListItem item in allOptions)
{
divTag.InnerHtml += string.Format(
"<div><input type=\"checkbox\" name=\"{0}\" id=\"{1}_{2}\" " +
"value=\"{2}\" {3} /><label for=\"{1}_{2}\">{4}</label></div>",
propertyName,
TagBuilder.CreateSanitizedId(propertyName),
item.Value,
selectedValues.Contains(item.Value) ? "checked=\"checked\"" : string.Empty,
item.Text);
}
return MvcHtmlString.Create(divTag.ToString());
}
我还在试验中,但这似乎可以与默认绑定器配合使用,并在提交后保留用户的选择。隐藏字段,真的吗?在HTML5中会有用吗?这感觉很疯狂,但我宁愿这样做,也不想因为ModelState.IsValid为false而为下拉列表和复选框列表访问我的数据库。
public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper, List<SelectListItem> list, string ModelCollectionName)
{
var sb = new StringBuilder();
if (list != null)
{
int i = 0;
foreach (var l in list)
{
string collectionNameIndex = String.Format("{0}[{1}]", ModelCollectionName, i);
var hiddenName = new TagBuilder("input");
hiddenName.Attributes.Add(new KeyValuePair<string, string>("type", "hidden"));
hiddenName.Attributes.Add(new KeyValuePair<string, string>("name", String.Format("{0}.{1}", collectionNameIndex, "Text")));
hiddenName.Attributes.Add(new KeyValuePair<string, string>("value", l.Text));
var hiddenValue = new TagBuilder("input");
hiddenValue.Attributes.Add(new KeyValuePair<string, string>("type", "hidden"));
hiddenValue.Attributes.Add(new KeyValuePair<string, string>("name", String.Format("{0}.{1}", collectionNameIndex, "Value")));
hiddenValue.Attributes.Add(new KeyValuePair<string, string>("value", l.Value));
var checkBoxTag = htmlHelper.CheckBox(String.Format("{0}.{1}", collectionNameIndex, "Selected"), l.Selected);
var labelTag = new TagBuilder("label");
labelTag.Attributes.Add(new KeyValuePair<string, string>("for", String.Format("{0}.{1}", collectionNameIndex, "Name")));
labelTag.SetInnerText(l.Text);
sb.Append(hiddenName);
sb.Append(hiddenValue);
sb.Append(checkBoxTag);
sb.Append(labelTag);
sb.Append("<br/>");
i++;
}
}
return MvcHtmlString.Create(sb.ToString());
}
虽然只有微软的员工才能回答为什么这种辅助方法不存在,但您可以尝试以下方法:
模型:
public class MyViewModel
{
public bool[] Values { get; set; }
}
控制器:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel
{
Values = new[] { true, false, true, false }
});
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
视图:
<% using (Html.BeginForm()) { %>
<%: Html.EditorFor(x => x.Values) %>
<input type="submit" value="OK" />
<% } %>
正如您所看到的,EditorFor
将处理所有必要的内容。
ListBoxFor
的行为。 - VenemoListBoxFor
生成 <select>
并接受不同类型。你需要什么? - Darin Dimitrov你可能会对 Jeremiah Clark 的 MVC CheckBoxList Helper 文章感兴趣(不幸的是,它的日期是2008年11月,涉及MVC 1)。