在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();
}