TextBoxFor控件的问题:
1:自带了样式,再用bootstrap样式会有冲突。
2:要加水印,js事件,限制输入长度比较麻烦。
因此需要对textboxfor控件进行扩展。
目标:
1:能使用bootstrap样式。
2:能复用mvc的验证。
3:可以方便的添加水印。
4:能限制输入字符的长度。
5:采用一些命名约定,使用扩展控件。(说白了,就是日期类型的直接给上边加上调用日期控件的调用。)
解决方案
最容易想到的解决办法就是直接写个扩展方法,进行字符串拼接生成控件。使用的时候:@BootStrap.TextBoxFor(u=>u.Email)
最终生成:
实现时候,悲催了。发现很难直接获取属性的验证信息,难道要自己再写反射,读取特性。生成对应的验证信息。
另一条路,借助mvc的htmlhelper来完成了。
public static MvcHtmlString BsTextBoxFor(this HtmlHelper htmlHelper, Expression > expression,string css="", string placeholder="") { TagBuilder tagBuilder = new TagBuilder("input"); ModelMetadata metadata = ModelMetadata.FromLambdaExpression (expression, htmlHelper.ViewData); //tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(ExpressionHelper.GetExpressionText(expression), metadata)); string name = ExpressionHelper.GetExpressionText(expression); //var vas = htmlHelper.GetUnobtrusiveValidationAttributes(name, metadata); htmlHelper.ValidateFor(expression); tagBuilder.MergeAttribute("name",name); tagBuilder.GenerateId(name); tagBuilder.MergeAttribute("type","text"); //核心代码,直接通过这个方法可以获取属性上的验证信息,如:“data-val= ....”。有一点要注意,在一个属性上,调用了这个方法完成后。mvc底层代码会自动释放这个验证对象。也就是说,一个属性的输入文本框只会第一个上边会生成相关的验证。
var vas = htmlHelper.GetUnobtrusiveValidationAttributes(name,metadata); if (!string.IsNullOrEmpty(placeholder)) { tagBuilder.MergeAttribute("placeholder",placeholder); } //string类型,看有没长度限制,如果有,增加maxlength,minlength if (metadata.ModelType == typeof (string)) { var len = metadata.ContainerType.GetProperty(name).GetCustomAttribute(typeof(StringLengthAttribute)); if (len != null) { var stringlength = (StringLengthAttribute) len; if (stringlength.MaximumLength > 0) { tagBuilder.MergeAttribute("maxlength", stringlength.MaximumLength.ToString()); } if (stringlength.MinimumLength > 0) { tagBuilder.MergeAttribute("minlength", stringlength.MinimumLength.ToString()); } } } //如果model值不为,null,进行赋值。 if (metadata.Model != null) { todo:还要完善。 tagBuilder.MergeAttribute("value",metadata.Model.ToString()); } tagBuilder.MergeAttributes(vas); tagBuilder.AddCssClass("form-control"); if (!string.IsNullOrEmpty(css)) { tagBuilder.AddCssClass(css); } //约定,属性名以day或者date结束的属性为日体,为其增加日期选择功能。 if (name.ToLower().EndsWith("day") || name.ToLower().EndsWith("date")) { tagBuilder.MergeAttribute("onclick", "WdatePicker()"); } return new MvcHtmlString(tagBuilder.ToString()); }
最终实现效果:
View部分代码:
@Html.BsLabelFor(model => model.Email)@*@Html.TextBoxFor(model => model.Email, new { @class = "form-control" })*@ @Html.BsTextBoxFor(model=>model.Email) @Html.ValidationMessageFor(model => model.Email, "", new { @class = "help-block" })@Html.BsLabelFor(model => model.Salary)$@Html.BsTextBoxFor(model => model.Salary).00@Html.ValidationMessageFor(model => model.Salary, "", new { @class = "help-block" })@Html.BsLabelFor(model => model.Code)@Html.BsTextBoxFor(model => model.Code)@Html.ValidationMessageFor(model => model.Code, "", new { @class = "help-block" })@Html.BsLabelFor(model => model.BirthDay)@Html.BsTextBoxFor(model => model.BirthDay)@Html.ValidationMessageFor(model => model.BirthDay)
viewModel代码:
public class VerifyModel { public Guid Id { get; set; } [DisplayName("用户名")] [Required] [StringLength(15)] [Remote("CheckName", "Form")] public string UserName { get; set; } [DisplayName("密码")] [Required] [StringLength(20,MinimumLength = 4)] [DataType(DataType.Password)] public string PassWord { get; set; } [DataType(DataType.Password)] [System.ComponentModel.DataAnnotations.Compare("PassWord", ErrorMessage = "两次输入密码不一致")] [DisplayName("确认密码")] public virtual string ConfirmPassWord { get; set; } [StringLength(50)] [DisplayName("邮箱")] [Required] [DataType(DataType.EmailAddress)] [RegularExpression(@".+")] public string Email { get; set; } [RegularExpression(@"1\d{10}", ErrorMessage = "请输入正确的手机号码")] [DisplayName("手机")] [Required] public string Phone { get; set; } [DisplayName("薪水")] [Required] public decimal Salary { get; set; } [RegularExpression(@"d{6}", ErrorMessage = "邮编为六位数字")] [DisplayName("邮编")] [Required] public string Code { get; set; } [DisplayName("生日")] [Required] public DateTime BirthDay { get; set; } }
最后:
配合T4模板,采用一些命名约定能更快捷的生成各种表单页面。