最近在使用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
{
///
/// HtmlHelper扩展
///
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);
}
///
/// 生成CheckBox列表
///
/// HtmlHelper
/// name属性
/// 每个SelectList外层
/// inputType
/// selectList
/// metadata
///
MvcHtmlString
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());
}
///
/// 生成CheckBox列表
///
/// HtmlHelper
///
/// name属性
///
MvcHtmlString
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);
}
///
/// 生成CheckBox列表
///
///
///
///
/// 每项分隔符的Tag名称
///
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);
}
///
/// 生成RadioButton列表
///
///
///
///
///
///
public static MvcHtmlString RadioButtonList( this HtmlHelper helper, IEnumerable < SelectListItem > selectList, string checkBoxName, string splitTag)
{
return InputList(helper, selectList, checkBoxName, splitTag, InputType.Radio);
}
///
/// 生成RadioButton列表
///
///
///
///
///
public static MvcHtmlString RadioButtonList( this HtmlHelper helper, IEnumerable < SelectListItem > selectList, string checkBoxName)
{
return InputList(helper, selectList, checkBoxName, null , InputType.Radio);
}
}
}
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
namespace Newborn.BSCommon
{
///
/// HtmlHelper扩展
///
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);
}
///
/// 生成CheckBox列表
///
/// HtmlHelper
/// name属性
/// 每个SelectList外层
/// inputType
/// selectList
/// metadata
///
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());
}
///
/// 生成CheckBox列表
///
/// HtmlHelper
///
/// name属性
///
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);
}
///
/// 生成CheckBox列表
///
///
///
///
/// 每项分隔符的Tag名称
///
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);
}
///
/// 生成RadioButton列表
///
///
///
///
///
///
public static MvcHtmlString RadioButtonList( this HtmlHelper helper, IEnumerable < SelectListItem > selectList, string checkBoxName, string splitTag)
{
return InputList(helper, selectList, checkBoxName, splitTag, InputType.Radio);
}
///
/// 生成RadioButton列表
///
///
///
///
///
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 >
< 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");//初始验证
new checkBoxList("RoleList", "hiddenRoleList");//初始验证
});
是为了让脚本去绑定事件,可能还会有更好的方式,这里有待研究。
页面上代码如下:
HTML部分
<
div
class
="select"
>
@Html.CheckBoxListFor(m=>m.RoleList,"li")
@Html.ValidationMessageFor(m => m.RoleList)
div >
@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;
}
}
}
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();
};
// 添加验证如验证框必须选择一定数量的验证
$.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();
};