今天公司要写学习总结,想着想着还是先写一篇关于MVC内部什么东东的博客整理整理再发表吧,一举两得。
之前写过了路由、过滤器等。今天就研究一下怎么自定义MVC控件吧。
本人技术小菜,不喜勿喷。。。。。(说这句话通常有两种情况,一种是牛人谦虚的说法,一种是怕受伤害提前准备个挡箭牌)
首先我们先去熟知一下MVC内部的那些控件是怎么实现的。
首先,Input标签是大佬,我给各位看管来上一小段Password的吧。
1 2 public static class InputExtensions { 3 public static MvcHtmlString Password(this HtmlHelper htmlHelper, string name) { 4 return Password(htmlHelper, name, null /* value */); 5 } 6 7 public static MvcHtmlString Password(this HtmlHelper htmlHelper, string name, object value) { 8 return Password(htmlHelper, name, value, null /* htmlAttributes */); 9 } 10 11 public static MvcHtmlString Password(this HtmlHelper htmlHelper, string name, object value, object htmlAttributes) { 12 return Password(htmlHelper, name, value, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); 13 } 14 15 public static MvcHtmlString Password(this HtmlHelper htmlHelper, string name, object value, IDictionary<string, object> htmlAttributes) { 16 return PasswordHelper(htmlHelper, null /* metadata */, name, value, htmlAttributes); 17 } 18 19 [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] 20 public static MvcHtmlString PasswordFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) { 21 return PasswordFor(htmlHelper, expression, null /* htmlAttributes */); 22 } 23 }
这定义的都是扩展方法,实现了重载,我们看到最后一个方法调用的是PasswordHelper 方法
1 private static MvcHtmlString PasswordHelper(HtmlHelper htmlHelper, ModelMetadata metadata, string name, object value, IDictionary<string, object> htmlAttributes) { 2 return InputHelper(htmlHelper, InputType.Password, metadata, name, value, false /* useViewData */, false /* isChecked */, true /* setId */, true /* isExplicitValue */, htmlAttributes); 3 }
但其最终调用的还是InputHelper方法,我们可以展开看看.....
1 private static MvcHtmlString InputHelper(HtmlHelper htmlHelper, InputType inputType, ModelMetadata metadata, string name, object value, bool useViewData, bool isChecked, bool setId, bool isExplicitValue, IDictionary<string, object> htmlAttributes) { 2 string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name); 3 if (String.IsNullOrEmpty(fullName)) { 4 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "name"); 5 } 6 7 TagBuilder tagBuilder = new TagBuilder("input"); 8 tagBuilder.MergeAttributes(htmlAttributes); 9 tagBuilder.MergeAttribute("type", HtmlHelper.GetInputTypeString(inputType)); 10 tagBuilder.MergeAttribute("name", fullName, true); 11 12 string valueParameter = Convert.ToString(value, CultureInfo.CurrentCulture); 13 bool usedModelState = false; 14 15 switch (inputType) { 16 case InputType.CheckBox: 17 bool? modelStateWasChecked = htmlHelper.GetModelStateValue(fullName, typeof(bool)) as bool?; 18 if (modelStateWasChecked.HasValue) { 19 isChecked = modelStateWasChecked.Value; 20 usedModelState = true; 21 } 22 goto case InputType.Radio; 23 case InputType.Radio: 24 if (!usedModelState) { 25 string modelStateValue = htmlHelper.GetModelStateValue(fullName, typeof(string)) as string; 26 if (modelStateValue != null) { 27 isChecked = String.Equals(modelStateValue, valueParameter, StringComparison.Ordinal); 28 usedModelState = true; 29 } 30 } 31 if (!usedModelState && useViewData) { 32 isChecked = htmlHelper.EvalBoolean(fullName); 33 } 34 if (isChecked) { 35 tagBuilder.MergeAttribute("checked", "checked"); 36 } 37 tagBuilder.MergeAttribute("value", valueParameter, isExplicitValue); 38 break; 39 case InputType.Password: 40 if (value != null) { 41 tagBuilder.MergeAttribute("value", valueParameter, isExplicitValue); 42 } 43 break; 44 default: 45 string attemptedValue = (string)htmlHelper.GetModelStateValue(fullName, typeof(string)); 46 tagBuilder.MergeAttribute("value", attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(fullName) : valueParameter), isExplicitValue); 47 break; 48 } 49 50 if (setId) { 51 tagBuilder.GenerateId(fullName); 52 } 53 54 // If there are any errors for a named field, we add the css attribute. 55 ModelState modelState; 56 if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState)) { 57 if (modelState.Errors.Count > 0) { 58 tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName); 59 } 60 } 61 62 tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(name, metadata)); 63 64 if (inputType == InputType.CheckBox) { 65 // Render an additional <input type="hidden".../> for checkboxes. This 66 // addresses scenarios where unchecked checkboxes are not sent in the request. 67 // Sending a hidden input makes it possible to know that the checkbox was present 68 // on the page when the request was submitted. 69 StringBuilder inputItemBuilder = new StringBuilder(); 70 inputItemBuilder.Append(tagBuilder.ToString(TagRenderMode.SelfClosing)); 71 72 TagBuilder hiddenInput = new TagBuilder("input"); 73 hiddenInput.MergeAttribute("type", HtmlHelper.GetInputTypeString(InputType.Hidden)); 74 hiddenInput.MergeAttribute("name", fullName); 75 hiddenInput.MergeAttribute("value", "false"); 76 inputItemBuilder.Append(hiddenInput.ToString(TagRenderMode.SelfClosing)); 77 return MvcHtmlString.Create(inputItemBuilder.ToString()); 78 } 79 80 return tagBuilder.ToMvcHtmlString(TagRenderMode.SelfClosing); 81 }
该方法主要通过传递来的Input类型,还有一些name,value以及一些判断的界定来生产一个Input标签,最后返回一个MvcHtmlString对象。
其中实现我们就不做一一分析了,只是看看大概是如何实现的。
接下来我们自己定义一个简单的Input标签,类型为submit即提交的按钮。
1 namespace System.Web.Mvc.Html 2 { 3 public static class SubmitExtention 4 { 5 public const string DefaultSubmitValue = "提交"; 6 7 public static MvcHtmlString Submit(this HtmlHelper htmlHelper) 8 { 9 return Submit(htmlHelper); 10 } 11 12 public static MvcHtmlString Submit(this HtmlHelper htmlHelper, string value) 13 { 14 return Submit(htmlHelper, null, value); 15 } 16 17 public static MvcHtmlString Submit(this HtmlHelper htmlHelper, string name, string value) 18 { 19 return Submit(htmlHelper, name, value, null); 20 } 21 22 public static MvcHtmlString Submit(this HtmlHelper htmlHelper, string name, string value, IDictionary<string, string> attributes) 23 { 24 TagBuilder tag = new TagBuilder("input"); 25 tag.Attributes.Add("type", "submit"); 26 27 if (!string.IsNullOrEmpty(name)) 28 { 29 tag.Attributes.Add("name", name); 30 } 31 32 if (!string.IsNullOrEmpty(value)) 33 { 34 tag.Attributes.Add("value", value); 35 } 36 else 37 { 38 tag.Attributes.Add("value", DefaultSubmitValue); 39 } 40 41 if (null != attributes) 42 { 43 foreach (var attr in attributes) 44 { 45 tag.Attributes.Add(attr.Key, attr.Value); 46 } 47 } 48 return MvcHtmlString.Create(tag.ToString()); 49 } 50 } 51 }
好了,我们去视图里看看吧。
点出来了吧,小伙伴们惊喜吗?
呵呵,其实一点都不惊喜,不久一个扩展方法吗?
不积跬步无以至千里,慢慢来,以后的路还很长,写博客只是为了总结,忘了的时候翻出来看看,温习温习,权当做笔记咯。
注意:
在视图配置文件中没有添加引用的情况下,小伙伴们可能点不出。
如果不行,你们还是把命名空间改为System.Web.Mvc.Html,像我这样,不然是点不出来的。