將”ListControl”引入ASP.NET MVC
我們不僅可以建立相應的模板來根據Model後設資料控制種型別的資料在UI介面上的呈現方法,還可以透過一些擴充套件來控制Model後設資料本身。在某些情況下透過這兩者的結合往往可以解決很多特殊資料的呈現問題,我們接下來演示的例項就是典型的例子。[本文已經同步到《How ASP.NET MVC Works?》中]
傳統的ASP.NET具有一組重要的控制元件型別叫做列表控制元件(ListControl),它的子類包括DropDownList、ListBox、RadioButtonList和CheckBoxList等。對於ASP.NET MVC來說,我們可以透過HtmlHelper/HtmlHelper
一、實現的效果
我們先來看看透過該擴充套件最終實現的效果。在透過Visual Studio的ASP.NET MVC專案模板建立的空Web應用中,我們定義一個作為Model表示員工的Employee型別。如下面的程式碼片斷所示,表示性別、學歷、部門和技能的屬性分別應用了RadioButtonListAttribute、DropdownListAttribute、ListBoxAttribute和CheckBoxListAttribubte四個特性。從名稱可以看出來,這四個特性分別代表了目標元素呈現在UI介面上的形式,即對應著傳統ASP.NET Web應用中的四種型別的列表控制元件:RadioButtonList、DropdownList、ListBox和CheckBoxList。特性中指定的字串表示預定義列表的名稱。
1: public class Employee
2: {
3: [DisplayName("姓名")]
4: public string Name { get; set; }
5:
6: [RadioButtonList("Gender")]
7: [DisplayName("性別")]
8: public string Gender { get; set; }
9:
10: [DropdownList("Education")]
11: [DisplayName("學歷")]
12: public string Education { get; set; }
13:
14: [ListBox("Department")]
15: [DisplayName("所在部門")]
16: public IEnumerableDepartments { get; set; }
17:
18: [CheckBoxList("Skill")]
19: [DisplayName("擅長技能")]
20: public IEnumerableSkills { get; set; }
21: }
在建立的預設HomeController中,我們定義瞭如下一個Index操作方法。在該方法中,我們建立了一個具體的Employee物件並對它的所有屬性進行了相應設定,最終將該物件呈現在預設的View中。
1: public class HomeController : Controller
2: {
3: public ActionResult Index()
4: {
5: Employee employee = new Employee
6: {
7: Name = "張三",
8: Gender = "M",
9: Education = "M",
10: Departments= new string[] { "HR", "AD" },
11: Skills = new string[] { "CSharp", "AdoNet" }
12: };
13: return View(employee);
14: }
15: }
如下所示的是上面的Index操作對應的View定義,這是一個以Model型別為Employee的強型別View,我們透過呼叫HtmlHelper
1: @model Employee
2:
@Html.LabelFor(m => m.Name) | @Html.EditorFor(m => m.Name) |
@Html.LabelFor(m => m.Gender) | @Html.EditorFor(m => m.Gender) |
@Html.LabelFor(m => m.Education) | @Html.EditorFor(m => m.Education) |
@Html.LabelFor(m => m.Departments) | @Html.EditorFor(m => m.Departments) |
@Html.LabelFor(m => m.Skills) | @Html.EditorFor(m => m.Skills) |
下圖體現了該Web應用執行時的效果。我們可以看到,四個屬性分別以四種不同的“列表控制元件”呈現出來,並且對應在它們上面的四個字定義的列表特性(RadioButtonListAttribute、DropdownListAttribute、ListBoxAttribute和CheckBoxListAttribubte)。
二、ListItem與ListProvider
現在對體現在上面演示例項的基於列表資料的UI定製的設計進行簡單地介紹。我們首先來定義如下一個表示列表中某個條目(列表項)的型別ListItem,簡單起見,我們緊緊定義Text和Value兩個屬性,它們分別表示顯示的文字和代表的值。比如對於一組表示國家的列表,列表項的Text屬性表示成國家名稱(比如“中國”),具體的值則可能是國家的程式碼(比如“CN”)。
1: public class ListItem
2: {
3: public string Text { get; set; }
4: public string Value { get; set; }
5: }
我們將提供列表資料的元件稱為ListProvider,它們實現了IListProvider介面。如下面的程式碼片斷所示,IListProvider具有唯一的方法GetListItems根據指定的列表名稱獲取所有的列表項。透過實現IListProvider,我們定義了一個預設的DefaultListProvider。簡單起見,DefaultListProvider直接透過一個靜態欄位模擬列表的儲存,在真正的專案中一般會儲存在資料庫中。DefaultListProvider維護了四組列表,分別表示性別、學歷、部門和技能,它們正好對應著Employee的四個屬性。
1: public interface IListProvider
2: {
3: IEnumerableGetListItems(string listName);
4: }
5: public class DefaultListProvider : IListProvider
6: {
7: private static Dictionary> listItems = new Dictionary >();
8: static DefaultListProvider()
9: {
10: var items = new ListItem[]{
11: new ListItem{ Text = "男", Value="M"},
12: new ListItem{ Text = "女", Value="F"}};
13: listItems.Add("Gender", items);
14:
15: items = new ListItem[]{
16: new ListItem{ Text = "高中", Value="H"} ,
17: new ListItem{ Text = "大學本科", Value="B"},
18: new ListItem{ Text = "碩士", Value="M"} ,
19: new ListItem{ Text = "博士", Value="D"}};
20: listItems.Add("Education", items);
21:
22: items = new ListItem[]{
23: new ListItem{ Text = "人事部", Value="HR"} ,
24: new ListItem{ Text = "行政部", Value="AD"},
25: new ListItem{ Text = "IT部", Value="IT"}};
26: listItems.Add("Department", items);
27:
28: items = new ListItem[]{
29: new ListItem{ Text = "C#", Value="CSharp"} ,
30: new ListItem{ Text = "ASP.NET", Value="AspNet"},
31: new ListItem{ Text = "ADO.NET", Value="AdoNet"}};
32: listItems.Add("Skill", items);
33: }
34: public IEnumerableGetListItems(string listName)
35: {
36: IEnumerableitems;
37: if (listItems.TryGetValue(listName, out items))
38: {
39: return items;
40: }
41: return new ListItem[0];
42: }
43: }
接下來我們定義如下一個ListProviders型別,它的靜態只讀屬性Current表示當前的ListProvider,而對當前ListProvider的註冊透過靜態方法SetListProvider來實現。如果沒有對當前ListProvider進行顯式註冊,則預設採用DefaultListProvider。
1: public static class ListProviders
2: {
3: public static IListProvider Current { get; private set; }
4: static ListProviders()
5: {
6: Current = new DefaultListProvider();
7: }
8: public static void SetListProvider(FuncproviderAccessor)
9: {
10: Current = providerAccessor();
11: }
12: }
三、透過對HtmlHelper/HtmlHelper的擴充套件生成“ListControl”的HTML
基於四種“列表控制元件”的HTML生成是透過定義HtmlHelper的擴充套件方法來實現的,如下面的程式碼所示,定義在ListControlExtensions中的四個擴充套件方法實現了針對這四種列表控制元件的UI呈現。引數listName表示使用的預定義列表的名稱,而value和values則表示繫結的值。RadioButtonList/DropdownList只允許單項選擇,而ListBox/CheckBoxList允許多項選擇,所以對應的值型別分別是string和IEnumerable
1: public static class ListControlExtensions
2: {
3: //其他成員
4: public static MvcHtmlString RadioButtonList( this HtmlHelper htmlHelper,string name, string listName, string value)
5: {
6: return RadioButtonCheckBoxList(htmlHelper, listName, item =>
7: htmlHelper.RadioButton(name, item.Value, value == item.Value));
8: }
9:
10: public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper, string name, string listName, IEnumerablevalues)
11: {
12: return RadioButtonCheckBoxList(htmlHelper, listName, item => CheckBoxWithValue(htmlHelper, name, values.Contains(item.Value), item.Value));
13: }
14:
15: public static MvcHtmlString ListBox(this HtmlHelper htmlHelper, string name, string listName, IEnumerablevalues)
16: {
17: var listItems = ListProviders.Current.GetListItems(listName);
18: ListselectListItems = new List ();
19: foreach (var item in listItems)
20: {
21: selectListItems.Add(new SelectListItem { Value = item.Value,
22: Text = item.Text,
23: Selected = values.Any(value => value == item.Value) });
24: }
25: return htmlHelper.ListBox(name, selectListItems);
26: }
27:
28: public static MvcHtmlString DropDownList(this HtmlHelper htmlHelper, string name, string listName, string value)
29: {
30: var listItems = ListProviders.Current.GetListItems(listName);
31: ListselectListItems = new List ();
32: foreach (var item in listItems)
33: {
34: selectListItems.Add(new SelectListItem { Value = item.Value,
35: Text = item.Text, Selected = value == item.Value});
36: }
37: return htmlHelper.DropDownList(name, selectListItems);
38: }
39: }
從上面的程式碼片斷可以看到,在ListBox和DropDownList方法中我們透過當前的ListProvider獲取指定列表名稱的所有列表項並生成相應的SelectListItem列表,最終透過呼叫HtmlHelper現有的擴充套件方法ListBox和DropDownList實現HTML的呈現。而RadioButtonList和MvcHtmlString最終呼叫了輔助方法RadioButtonCheckBoxList顯示了最終的HTML生成,該方法定義如下。
1: public static class ListControlExtensions
2: {
3: public static MvcHtmlString CheckBoxWithValue(this HtmlHelper htmlHelper, string name, bool isChecked, string value)
4: {
5: string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
6: ModelState modelState;
7:
8: //將ModelState設定為表示是否勾選布林值
9: if (htmlHelper.ViewData.ModelState.TryGetValue(fullHtmlFieldName, out modelState))
10: {
11: htmlHelper.ViewData.ModelState.SetModelValue(fullHtmlFieldName, new ValueProviderResult(isChecked, isChecked.ToString(), CultureInfo.CurrentCulture));
12: }
13: MvcHtmlString html;
14: try
15: {
16: html = htmlHelper.CheckBox(name, isChecked);
17: }
18: finally
19: {
20: //將ModelState還原
21: if (null != modelState)
22: {
23: htmlHelper.ViewData.ModelState[fullHtmlFieldName] = modelState;
24: }
25: }
26: string htmlString = html.ToHtmlString();
27: var index = htmlString.LastIndexOf('
28: //過濾掉型別為"hidden"的元素
29: XElement element = XElement.Parse(htmlString.Substring(0, index));
30: element.SetAttributeValue("value", value);
31: return new MvcHtmlString(element.ToString());
32: }
33:
34: private static MvcHtmlString RadioButtonCheckBoxList(HtmlHelper htmlHelper, string listName, FuncelementHtmlAccessor)
35: {
36: var listItems = ListProviders.Current.GetListItems(listName);
37: TagBuilder table = new TagBuilder("table");
38: TagBuilder tr = new TagBuilder("tr");
39: foreach (var listItem in listItems)
40: {
41: TagBuilder td = new TagBuilder("td");
42: td.InnerHtml += elementHtmlAccessor(listItem).ToHtmlString();
43: td.InnerHtml += listItem.Text;
44: tr.InnerHtml += td.ToString();
45: }
46: table.InnerHtml = tr.ToString();
47: return new MvcHtmlString(table.ToString());
48: }
49: }方法RadioButtonCheckBoxList在生成RadioButtonList和CheckBoxList的時候才用
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1020/viewspace-2810171/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- ASP.NET MVC路由ASP.NETMVC路由
- ASP.NET MVC ModuleASP.NETMVC
- ASP.NET MVC TemplateASP.NETMVC
- ASP.NET MVC ErrorASP.NETMVCError
- ASP.NET MVC FilterASP.NETMVCFilter
- UpdatePanel for ASP.NET MVCASP.NETMVC
- ASP.NET MVC與ASP.NET WebFormASP.NETMVCWebORM
- [ASP.NET MVC 小牛之路]01 - 理解MVC模式ASP.NETMVC模式
- Asp.Net MVC HttpPost用法ASP.NETMVCHTTP
- ASP.NET MVC 反射例子ASP.NETMVC反射
- Asp.Net MVC 快取ASP.NETMVC快取
- Asp.Net MVC 使用 AjaxASP.NETMVC
- ASP.NET MVC ValidationASP.NETMVC
- ASP.NET MVC: Membership, OAuthASP.NETMVCOAuth
- ASP.NET MVC系列:AreaASP.NETMVC
- ASP.NET MVC系列:ModelASP.NETMVC
- AJAX Panels with ASP.NET MVCASP.NETMVC
- ASP.NET MVC 之 AJAXASP.NETMVC
- ASP.NET MVC和AJAXASP.NETMVC
- ASP.NET MVC 介紹ASP.NETMVC
- ASP.NET AJAX 是ASP.NET 3.5 才引入的ASP.NET
- ASP.NET MVC 4使用PagedList.Mvc分頁ASP.NETMVC
- 【輝郎】ASP.NET MVC深度接觸:ASP.NET MVC請求生命週期ASP.NETMVC
- ASP.Net MVC過濾器ASP.NETMVC過濾器
- asp.net core mvc 分頁ASP.NETMVC
- ASP.NET MVC – 安全簡介ASP.NETMVC
- ASP.NET MVC – 模型簡介ASP.NETMVC模型
- ASP.NET MVC 使用 Datatables (1)ASP.NETMVC
- ASP.NET MVC 使用 Datatables (2)ASP.NETMVC
- Asp.net mvc 知多少(二)ASP.NETMVC
- Asp.net MVC – ControllerASP.NETMVCController
- Asp.Net MVC 捆綁(Bundle)ASP.NETMVC
- ASP.NET MVC TagBuilder使用ASP.NETMVCUI
- 筆記:ASP.NET MVC安全筆記ASP.NETMVC
- ASP.NET 4.5 MVC4.0ASP.NETMVC
- 【 Jeffrey Zhao】UpdatePanel for ASP.NET MVCASP.NETMVC
- ASP.NET MVC之初體驗ASP.NETMVC
- AJAX基於ASP.NET MVCASP.NETMVC