如何在 ASP.NET MVC 中创建 CheckBoxListFor 扩展方法?
Posted
技术标签:
【中文标题】如何在 ASP.NET MVC 中创建 CheckBoxListFor 扩展方法?【英文标题】:How to create a CheckBoxListFor extension method in ASP.NET MVC? 【发布时间】:2011-04-22 19:25:33 【问题描述】:我知道在 ASP.NET MVC html helper 扩展方法中有一个ListBoxFor
扩展方法,但我一直认为复选框列表比列表框更易于使用。
在良好的旧 WebForms 中有一个非常方便的 CheckBoxList
控件,但显然现在已经不存在了。
问题是,为什么在 ASP.NET MVC 中没有办法创建复选框列表?我如何编写自己的扩展方法来创建复选框列表并以类似ListBoxFor
的行为方式运行?
【问题讨论】:
【参考方案1】:这里是 CheckBoxListFor 的强类型 HtmlHelper,它将所选项目作为视图数据模型中的数组处理。我选择不包装 Html.CheckBox 或 Html.CheckBoxFor 方法,因为我不想在我的复选框列表中隐藏“假”字段。
请随时改进并重新发布:-)
//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());
【讨论】:
谢谢,这似乎就是我想要的。回家后试试看。 经过一些修改,我成功地让它按我想要的方式工作。非常感谢您的代码! :) @RafaelSoares 你打算做什么样的验证?至少有一个必须打勾或类似的东西? @RafaelSoares - 在这种情况下,我倾向于使用隐藏字段,例如“CheckboxChecked”没有初始值,上面有“必需”验证消息。然后我将一些 jquery 连接到复选框,以便如果一个或多个复选框被“选中”,则隐藏字段中的值设置为 true|yes|ok 或其他任何值。如果没有检查,只需从隐藏字段中删除值,验证就可以工作了。 如果你将这个嵌套在 EditorFor 中,它将无法正确绑定。我必须从 htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(modelMetadata.PropertyName); 设置 propertyName 变量然后使用带有 TagBuilder.CreateSanitizedId() 的经过清理的 id【参考方案2】:我仍在尝试,但这似乎与默认活页夹相处融洽,并在发布后保留用户选择。隐藏字段,真的吗? ..这会在html5中飞行吗?这感觉很疯狂,但我宁愿这样做,也不愿仅仅因为 ModelState.IsValid 为假而点击我的数据库以获取下拉列表和复选框列表。
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());
【讨论】:
【参考方案3】:虽然微软员工可能是唯一可以回答为什么不存在此类帮助方法的人,但您可以尝试:
型号:
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
的行为。
你能再具体一点吗? ListBoxFor
生成 <select>
并接受不同的类型。你到底需要什么?【参考方案4】:
您可能对 Jeremiah Clark 的 CheckBoxList Helper for MVC 文章感兴趣(不幸的是,它的日期为 2008 年 11 月,涉及 MVC 1)。
【讨论】:
这篇文章不错,但写的时候并没有考虑到强类型的 HTML 助手。以上是关于如何在 ASP.NET MVC 中创建 CheckBoxListFor 扩展方法?的主要内容,如果未能解决你的问题,请参考以下文章
我们如何使用 EF 在 ASP.Net MVC 应用程序中创建 3 层架构?
如何在 Visual Studio 2017 的 ASP.NET MVC 中创建自定义生成/脚手架模板(Razor)?
如何在 ASP .net MVC 4 应用程序的 HTML5 中创建带有可点击选项的水平条形图? [关闭]