在ASP.NET MVC P5中,当你使用这样的方法输出CheckBox:<%=Html.CheckBox("checkTest")%>,在浏览器上除了你期望看到的代码外,还有一个name和CheckBox相同的hidden域。这就导致了一个问题:当这个表单被提交时,hidden(name="checkTest",value="true")和input:checkbox(name="checkTest",value="false")会同时被提交,并且hidden域是强制的,导致在服务器端Request中,你得到的Request.Form["checkTest"]将可能是这样的:"false,true"。 所以在P5中使用Html.CheckBox()的时候要注意到这个bug。解决的方法很简单:不要用他。
但是如果你同时还希望用HtmlHelper偷懒的话,我这里提供了一个和P4中Html.Helper方法兼容的扩展,并且还比官方的方法更好——和label实现了绑定。
其实没有什么难度,和别的HtmlHelper扩展是一样的。这里给出基本实现:
Code
public static class CheckBoxExtensions
{
public static string CheckBox(this HtmlHelper helper, string name, string text, string value, bool isChecked)
{
return CheckBox(helper, name, text, value, isChecked,null);
}
public static string CheckBox(this HtmlHelper helper, string name, string text, string value, bool isChecked, object htmlAttributes)
{
var setHash = htmlAttributes.ToAttributeList();
string attributeList = string.Empty;
if (setHash != null)
attributeList = setHash;
return string.Format("<input id=\"{0}\" name=\"{0}\" value=\"{1}\" {2} type=\"checkbox\" {4}/>{3}",
name, value, isChecked ? "checked=\"checked\"" : "",
string.IsNullOrEmpty(text) ? "" : string.Format("<label id=\"{0}\" for=\"{1}\">{2}</label>", name + "_label", name, text),
attributeList);
}
}
如果有朋友仔细看过P5的源码,会发现这个问题可能不只在CheckBox中发生,而是被扩大到了input标签中。写这篇文章旨在请大家留意这个bug,并且完善自己的扩展方法。
补充一下:
关于上面代码中的var setHash = htmlAttributes.ToAttributeList();中,ToAttributeList()这个扩展方法,直接复制代码的朋友可能无法一次性通过编译,是因为这个方法存在于早先ASP.NET MVC版本的Toolkit中,现在似乎已经被删除了,但这个方法确实很实用,我把这个ToAttributeList()的代码也发上来:
Code
/// <summary>
/// Creates a simple {0}='{1}' list based on current object state.
/// </summary>
public static string ToAttributeList(this object o) {
StringBuilder sb = new StringBuilder();
if (o != null) {
Hashtable attributeHash = GetPropertyHash(o);
string resultFormat = " {0}=\"{1}\"";
foreach (string attribute in attributeHash.Keys) {
sb.AppendFormat(resultFormat, attribute.Replace("_", ""), attributeHash[attribute]);
}
}
return sb.ToString();
}
/// <summary>
/// Creates a simple {0}='{1}' list based on current object state. Ignores the passed-in string[] items
/// </summary>
/// <param name="o"></param>
/// <param name="ignoreList"></param>
/// <returns></returns>
public static string ToAttributeList(this object o, params object[] ignoreList) {
Hashtable attributeHash = GetPropertyHash(o);
string resultFormat = "{0}=\"{1}\" ";
StringBuilder sb = new StringBuilder();
foreach (string attribute in attributeHash.Keys) {
if (!ignoreList.Contains(attribute)) {
sb.AppendFormat(resultFormat, attribute, attributeHash[attribute]);
}
}
return sb.ToString();
}