前面幾篇文章介紹了一下ASP.NET MVC中的一些基礎,今天我們一起來學習一下在ASP.NET MVC中控件的封裝。在頁面中我們會經常使用到Html對象,來程序控件,當然這里的控件不是說ASP.NET中包含很多ViewState或其他信息的控件。在ASP.NET MVC中控件就是擴展方法,主要對HtmlHelper實例的擴展,不過這里主要會提到CheckBoxList和RadioButtonList的擴展,因為在微軟自帶的控件中是沒有這兩個控件存在的,所以我們需要自己擴展。最后還會介紹一下,Html.CheckBoxFor這個控件在使用時會有兩個值,在服務端進行判斷的結果。
ASP.NET MVC(包含MVC3.0,MVC4.0)中的控件都在System.Web.Mvc中,這里需要了解一下HtmlMvcString和普通的string的區別。在我看來HtmlMvcString就是對string進行編碼,使得瀏覽器能夠正確解析HTML字符串。這樣在前台顯示時就不需要使用Html.Raw方法對字符串進行編碼,否則顯示的字符串將不會解析成HTML代碼。這個只需了解就可以了,有興趣可以試試就知道所以然了,所以MVC控件都需要返回這個對象。
在ASP.NET MVC中,lumbda表達式是很經常用的,而且非常好用。在頁面中聲明了一個模型,那樣就可以使用lumbda表達式進行實例的賦值和判斷,當然在對控件擴展時就會預見到表達式的使用,這些都是.NET3.5的特性,這里就不多贅述。
2 /// 復選框擴展。
3 /// </summary>
4 /// <typeparam name="TModel"> 模型類型。 </typeparam>
5 /// <typeparam name="TProperty"> 屬性類型。 </typeparam>
6 /// <param name="helper"> HTML輔助方法。 </param>
7 /// <param name="expression"> lambda表達式。 </param>
8 /// <param name="selectList"> 選擇項。 </param>
9 /// <param name="htmlAttributes"> HTML屬性。 </param>
10 /// <returns> 返回復選框MVC的字符串。 </returns>
11 public static MvcHtmlString CheckBoxListFor<TModel, TProperty>( this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, ButtonFormatter formatter = ButtonFormatter.Horizontal, IDictionary< string, object> htmlAttributes = null)
12 {
13 if(selectList == null || expression == null)
14 return MvcHtmlString.Empty;
15 string name = ExpressionHelper.GetExpressionText(expression);
16 List< string> values = null;
17 object obj = helper.ViewData.Eval(name);
18 if(obj != null)
19 values = obj.ToString().Split< string>();
20 else
21 values = new List< string>();
22
23 StringBuilder sb = new StringBuilder();
24 int index = 0;
25 foreach( var item in selectList)
26 {
27 TagBuilder tag = new TagBuilder( " input ");
28 tag.MergeAttributes< string, object>(htmlAttributes);
29 tag.MergeAttribute( " type ", " checkbox ", true);
30 tag.MergeAttribute( " name ", name, true);
31 tag.MergeAttribute( " id ", name + index, true);
32 tag.MergeAttribute( " value ", item.Value, true);
33 if(values.Contains(item.Value))
34 tag.MergeAttribute( " checked ", " checked ", true);
35 sb.AppendLine(tag.ToString(TagRenderMode.SelfClosing) + " ");
36 TagBuilder label = new TagBuilder( " label ");
37 label.MergeAttribute( " for ", name + index);
38 label.InnerHtml = item.Text;
39 sb.AppendLine(label.ToString());
40 if(formatter == ButtonFormatter.Vertical)
41 sb.AppendLine( " <br /> ");
42 index++;
43 }
44 return new MvcHtmlString(sb.ToString());
45 }
46
47 /// <summary>
48 /// 復選框擴展。
49 /// </summary>
50 /// <typeparam name="TModel"> 模型類型。 </typeparam>
51 /// <typeparam name="TProperty"> 屬性類型。 </typeparam>
52 /// <param name="helper"> HTML輔助方法。 </param>
53 /// <param name="expression"> lambda表達式。 </param>
54 /// <param name="selectList"> 選擇項。 </param>
55 /// <param name="htmlAttributes"> HTML屬性。 </param>
56 /// <returns> 返回復選框MVC的字符串。 </returns>
57 public static MvcHtmlString CheckBoxListFor<TModel, TProperty>( this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, ButtonFormatter formatter, object htmlAttributes)
58 {
59 return helper.CheckBoxListFor<TModel, TProperty>(expression, selectList, formatter, new RouteValueDictionary(htmlAttributes));
60 }
61
62 /// <summary>
63 /// 枚舉復選框擴展。
64 /// </summary>
65 /// <typeparam name="TModel"> 模型類型。 </typeparam>
66 /// <typeparam name="TProperty"> 屬性類型。 </typeparam>
67 /// <param name="helper"> HTML輔助方法。 </param>
68 /// <param name="expression"> lambda表達式。 </param>
69 /// <param name="selectList"> 選擇項。 </param>
70 /// <param name="htmlAttributes"> HTML屬性。 </param>
71 /// <returns> 返回復選框MVC的字符串。 </returns>
72 public static MvcHtmlString CheckBoxListFor<TModel, TProperty>( this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, ButtonFormatter formatter = ButtonFormatter.Horizontal, object htmlAttributes = null, string classKey = Globals.Resource)
73 {
74 var selectList = new List<SelectListItem>();
75 Globals.ForEach<TProperty>(p => {
76 selectList.Add( new SelectListItem { Text = Globals.GetGlobalResourceByKey(p, classKey), Value = p.ToString() });
77 });
78 return helper.CheckBoxListFor<TModel, TProperty>(expression, selectList, formatter, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
79 }
上面的代碼各位有需要可以直接復制編譯后就可以使用了,其他涉及的資源的可以修改一下。而ButtonFormatter是一個枚舉類,主要用於設計橫排還是豎排的樣式,其他沒什么作用。這樣我們就可以很快的再前台使用CheckBoxList控件了,注意不是所有的頁面都有模型,或者說不是所有CheckBoxList都可以使用lumbda表達式來進行賦值等設置的,所以最好擴展一下CheckBoxList控件,那樣在各種情況都可以使用。
以上是我早期擴展的一個控件,其實很多地方都可以改的,比如屬性轉換,匿名類型可以直接實例化為RouteValueDictionary的,他的構造函數里就有這個。其中Globals.ForEach是我對枚舉迭代的一個擴展,即是循環枚舉中的每一個值顯示出來。而RadioButtonList的擴展和CheckBoxList的擴展是差不多的,只要標記替換一下就可以了,不過在大部分情況下比較少用,因為很多地方都被DropDownList替代。
下面介紹一下在使用CheckBox時,服務端獲取是否選中的方法。假如你使用過這個控件就會發現,呈現的HTML代碼中包含兩個checkbox的input,只是其中一個被隱藏了,當我們使用submit按鈕提交時,在服務端獲得的值就會包含兩個input的值。為了解決這個問題,我們需要判斷一下到底有沒有被選中,不難發現,如果沒有被選中,這服務端獲取得到的值就只有一個False的值,如果選中了就會有兩個,一個True一個False,所以我們需要判斷到底服務端獲得的第一個值是False還是True,具體代碼可以看下面。
1 /// <summary>
3 /// </summary>
4 /// <param name="form"> 路由實例對象。 </param>
5 /// <param name="key"> 路由鍵。 </param>
6 /// <param name="defaultValue"> 返回默認值。 </param>
7 /// <returns> 返回是否被選中。 </returns>
8 public static bool IsChecked( this FormCollection form, string key, bool defaultValue = false)
9 {
10 var values = form.GetValues(key);
11 if(values!= null)
12 return values[ 0].To< bool>(defaultValue);
13 return defaultValue;
14 }
15
16 /// <summary>
17 /// 判斷是否被選中。
18 /// </summary>
19 /// <param name="request"> 路由實例對象。 </param>
20 /// <param name="key"> 路由鍵。 </param>
21 /// <param name="defaultValue"> 返回默認值。 </param>
22 /// <returns> 返回是否被選中。 </returns>
23 public static bool IsChecked( this HttpRequestBase request, string key, bool defaultValue = false)
24 {
25 var values = request.Form.GetValues(key);
26 if(values != null)
27 return values[ 0].To< bool>(defaultValue);
28 return defaultValue;
29 }
其中To這個方法是我封裝類型轉換的方法,由於本系列沒有一個良好的規划,想到哪里就寫到哪里,很多達人看了可能不會有連續性。主要我還是推薦學基礎可以到MSDN或博客園里也有按照微軟Tutorial順序寫的教程,由於時間的關系今天到此結束。