最近在使用MVC進行開發時,使用進行用戶端的輸入驗證,加上使用MVC3的新視圖引擎感覺還是挺方便的,不用自己去寫很多js了,並且效果也能讓人接受
可是遇上要向外輸出比如一個CheckBox列表時就糾結了,驗證代碼還得自己去寫,這樣就造成了用戶端採用了兩套驗證,感覺不統一也不優雅,於是就琢磨了一下,便有了如下實現方式。
HtmlHelper的擴充類主要包括CheckBoxList,CheckBoxListFor等方法,有了這些方法,你可以這樣產生checkBox 列表
@Html.CheckBoxListFor(m=>m.RoleList,"li")
下來就是擴充的全部代碼
HtmlHelperExtention.cs
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
namespace Newborn.BSCommon
{
/// <summary>
/// HtmlHelper擴充
/// </summary>
public static class HtmlHelperExtention
{
public static MvcHtmlString InputList(this HtmlHelper helper, IEnumerable<SelectListItem> selectList, string checkBoxName, string splitTagName, InputType inputType)
{
return InputList(helper, null, selectList, checkBoxName,splitTagName, inputType);
}
/// <summary>
/// 產生CheckBox列表
/// </summary>
/// <param name="helper">HtmlHelper</param>
/// <param name="checkBoxName">name屬性</param>
/// <param name="splitTagName">每個SelectList外層</param>
/// <param name="inputType">inputType</param>
/// <param name="selectList">selectList</param>
/// <param name="metadata">metadata</param>
/// <returns>MvcHtmlString</returns>
public static MvcHtmlString InputList(this HtmlHelper helper,ModelMetadata metadata, IEnumerable<SelectListItem> selectList, string checkBoxName, string splitTagName, InputType inputType)
{
if (helper == null) throw new ArgumentNullException("helper");
if (selectList == null) throw new ArgumentNullException("selectList");
if (string.IsNullOrEmpty(checkBoxName)) throw new ArgumentNullException("checkBoxName");
StringBuilder sb = new StringBuilder();
int idIndex = 0;
TagBuilder tagBuilder = new TagBuilder("span");
foreach (SelectListItem item in selectList)
{
TagBuilder splitTagBuilder = null;
if (!string.IsNullOrEmpty(splitTagName))
splitTagBuilder = new TagBuilder(splitTagName);
TagBuilder checkTagBuilder = new TagBuilder("input");
checkTagBuilder.Attributes["type"] = inputType.ToString();
checkTagBuilder.Attributes["name"] = checkBoxName;
checkTagBuilder.Attributes["value"] = item.Value;
string checkBoxId = checkBoxName + "_id_" + idIndex;
checkTagBuilder.Attributes["id"] = checkBoxId;
if (item.Selected)
checkTagBuilder.Attributes["checked"] = "checked";
TagBuilder labelTagBuilder = new TagBuilder("label") { InnerHtml = helper.Encode(item.Text) };
labelTagBuilder.Attributes["for"] = checkBoxId;
string checkHtml = checkTagBuilder.ToString() + labelTagBuilder.ToString();
if (splitTagBuilder != null)
{
splitTagBuilder.InnerHtml += checkHtml;
sb.AppendLine(splitTagBuilder.ToString());
}
else
sb.AppendLine(checkHtml);
idIndex++;
}
TagBuilder hiddenTagBuilder = new TagBuilder("input");
hiddenTagBuilder.Attributes["type"] = "hidden";
hiddenTagBuilder.MergeAttribute("name", checkBoxName);
hiddenTagBuilder.MergeAttribute("id", "hidden"+ checkBoxName);
hiddenTagBuilder.MergeAttributes<string, object>(helper.GetUnobtrusiveValidationAttributes(checkBoxName, metadata));
tagBuilder.InnerHtml = hiddenTagBuilder + sb.ToString();
return MvcHtmlString.Create(tagBuilder.ToString());
}
/// <summary>
/// 產生CheckBox列表
/// </summary>
/// <param name="helper">HtmlHelper</param>
/// <param name="selectList"></param>
/// <param name="checkBoxName">name屬性</param>
/// <returns>MvcHtmlString</returns>
public static MvcHtmlString CheckBoxList(this HtmlHelper helper, IEnumerable<SelectListItem> selectList, string checkBoxName)
{
return helper.InputList(selectList, checkBoxName, null, InputType.CheckBox);
}
public static MvcHtmlString InputListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression,string splitTag,InputType inputType)
{
ModelMetadata modelMetadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData);
List<SelectListItem> list = ((List<SelectListItem>)modelMetadata.Model);
return htmlHelper.InputList(modelMetadata, list, modelMetadata.PropertyName, splitTag, inputType);
}
public static MvcHtmlString CheckBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
return htmlHelper.InputListFor(expression, "span",InputType.CheckBox);
}
public static MvcHtmlString CheckBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression,string splitTag)
{
return htmlHelper.InputListFor(expression, splitTag, InputType.CheckBox);
}
/// <summary>
/// 產生CheckBox列表
/// </summary>
/// <param name="helper"></param>
/// <param name="selectList"></param>
/// <param name="checkBoxName"></param>
/// <param name="splitTagName">每項分隔字元的Tag名稱</param>
/// <returns></returns>
public static MvcHtmlString CheckBoxList(this HtmlHelper helper, IEnumerable<SelectListItem> selectList, string checkBoxName, string splitTagName)
{
return InputList(helper, selectList, checkBoxName, splitTagName, InputType.CheckBox);
}
public static MvcHtmlString RadioBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
return htmlHelper.InputListFor(expression, "span", InputType.Radio);
}
/// <summary>
/// 產生RadioButton列表
/// </summary>
/// <param name="helper"></param>
/// <param name="selectList"></param>
/// <param name="checkBoxName"></param>
/// <param name="splitTag"></param>
/// <returns></returns>
public static MvcHtmlString RadioButtonList(this HtmlHelper helper, IEnumerable<SelectListItem> selectList, string checkBoxName, string splitTag)
{
return InputList(helper, selectList, checkBoxName, splitTag, InputType.Radio);
}
/// <summary>
/// 產生RadioButton列表
/// </summary>
/// <param name="helper"></param>
/// <param name="selectList"></param>
/// <param name="checkBoxName"></param>
/// <returns></returns>
public static MvcHtmlString RadioButtonList(this HtmlHelper helper, IEnumerable<SelectListItem> selectList, string checkBoxName)
{
return InputList(helper, selectList, checkBoxName, null, InputType.Radio);
}
}
}
由於使用到用戶端驗證所以要引用如下的js檔案。
指令碼部分
<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/Custom/jquery.validate.unobtrusive.extension.js")" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
new checkBoxList("RoleList", "hiddenRoleList");//初始驗證
});
</script>
頁面上還要寫這個一句
$(function () {
new checkBoxList("RoleList", "hiddenRoleList");//初始驗證
});
是為了讓指令碼去綁定事件,可能還會有更好的方式,這裡有待研究。
頁面上代碼如下:
HTML部分
<div class="select">
@Html.CheckBoxListFor(m=>m.RoleList,"li")
@Html.ValidationMessageFor(m => m.RoleList)
</div>
ListSlectRangeAttribute.cs 檔案
View Code
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace Newborn.BSCommon
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public class ListSlectRangeAttribute : ValidationAttribute, IClientValidatable
{
private const string errFormat = "該項最少選擇項為{0}最多選擇項為{1}";
public ListSlectRangeAttribute()
{
MinSelected = 0;
MaxSelected = -1;
}
public int MinSelected { get; set; }
public int MaxSelected { get; set; }
public override bool IsValid(object value)
{
return true;
}
public override string FormatErrorMessage(string name)
{
return string.Format(errFormat, MinSelected > 0 ? MinSelected.ToString() : "不限", MaxSelected > 0 ? MaxSelected.ToString() : "不限");
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
ModelClientValidationRule rule = new ModelClientValidationRule
{
ValidationType = "list",
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName())
};
rule.ValidationParameters["min"] = MinSelected;
rule.ValidationParameters["max"] = MaxSelected;
yield return rule;
}
}
}
jquery.validate.unobtrusive.extension.js檔案主要完成用戶端如checkbox列表的驗證,細心的朋友會發現因為checkbox列表是多個input所以我沒有基於它來做,而是採用一個隱藏欄位還記錄現在選擇的項數目(目前只記錄選擇了多少項,沒記錄選擇的項值之類的,不過目前暫無此類需求,如果有擴充起來也行方便)。
//by xianhong
//添加驗證如驗證框必須選擇一定數量的驗證
$.validator.addMethod("maxminselected", function (value, element, param) {
var min = param[0];
var max = param[1];
if (value >= min && (max <= 0 || value <= max))
return true;
return false;
});
$.validator.unobtrusive.adapters.addMinMax("list", "min", "max", "maxminselected");
var checkBoxList = function (name/*input name屬性*/, hiddenId/*記錄選擇的隱藏欄位*/) {
this.checkedCount = function () {
var selected = $("input[name='" + name + "']:checked");
return selected.length;
};
this.All = function () {
return $("input[name='" + name + "']");
};
this.BindClick = function () {
var thisobj = this;
this.All().click(function () {
$("#" + hiddenId).val(thisobj.checkedCount());
});
};
this.BindClick();
};