傳統的ASP.NET具有一組重要的控件類型叫做清單控件(ListControl),它的子類包括DropDownList、ListBox、RadioButtonList和CheckBoxList等。對于ASP.NET
我們先來看看通過該擴充最終實作的效果。在通過Visual Studio的ASP.NET MVC項目模闆建立的空Web應用中,我們定義一個作為Model表示員工的Employee類型。如下面的代碼片斷所示,表示性别、學曆、部門和技能的屬性分别應用了RadioButtonListAttribute、DropdownListAttribute、ListBoxAttribute和CheckBoxListAttribubte四個特性。從名稱可以看出來,這四個特性分别代表了目标元素呈現在UI界面上的形式,即對應着傳統ASP.NET
Web應用中的四種類型的清單控件:RadioButtonList、DropdownList、ListBox和CheckBoxList。特性中指定的字元串表示預定義清單的名稱。
在建立的預設HomeController中,我們定義了如下一個Index操作方法。在該方法中,我們建立了一個具體的Employee對象并對它的所有屬性進行了相應設定,最終将該對象呈現在預設的View中。
如下所示的是上面的Index操作對應的View定義,這是一個以Model類型為Employee的強類型View,我們通過調用HtmlHelper<TModel>的模闆方法EditorFor将作為Model的Employee對象的所有屬性以編輯模式呈現出來。
下圖展現了該Web應用運作時的效果。我們可以看到,四個屬性分别以四種不同的“清單控件”呈現出來,并且對應在它們上面的四個字定義的清單特性(RadioButtonListAttribute、DropdownListAttribute、ListBoxAttribute和CheckBoxListAttribubte)。

現在對展現在上面示範執行個體的基于清單資料的UI定制的設計進行簡單地介紹。我們首先來定義如下一個表示清單中某個條目(清單項)的類型ListItem,簡單起見,我們緊緊定義Text和Value兩個屬性,它們分别表示顯示的文字和代表的值。比如對于一組表示國家的清單,清單項的Text屬性表示成國家名稱(比如“中國”),具體的值則可能是國家的代碼(比如“CN”)。
我們将提供清單資料的元件稱為ListProvider,它們實作了IListProvider接口。如下面的代碼片斷所示,IListProvider具有唯一的方法GetListItems根據指定的清單名稱擷取所有的清單項。通過實作IListProvider,我們定義了一個預設的DefaultListProvider。簡單起見,DefaultListProvider直接通過一個靜态字段模拟清單的存儲,在真正的項目中一般會儲存在資料庫中。DefaultListProvider維護了四組清單,分别表示性别、學曆、部門和技能,它們正好對應着Employee的四個屬性。
接下來我們定義如下一個ListProviders類型,它的靜态隻讀屬性Current表示目前的ListProvider,而對目前ListProvider的注冊通過靜态方法SetListProvider來實作。如果沒有對目前ListProvider進行顯式注冊,則預設采用DefaultListProvider。
基于四種“清單控件”的HTML生成是通過定義HtmlHelper的擴充方法來實作的,如下面的代碼所示,定義在ListControlExtensions中的四個擴充方法實作了針對這四種清單控件的UI呈現。參數listName表示使用的預定義清單的名稱,而value和values則表示綁定的值。RadioButtonList/DropdownList隻允許單項選擇,而ListBox/CheckBoxList允許多項選擇,是以對應的值類型分别是string和IEnumerable<string>。
從上面的代碼片斷可以看到,在ListBox和DropDownList方法中我們通過目前的ListProvider擷取指定清單名稱的所有清單項并生成相應的SelectListItem清單,最終通過調用HtmlHelper現有的擴充方法ListBox和DropDownList實作HTML的呈現。而RadioButtonList和MvcHtmlString最終調用了輔助方法RadioButtonCheckBoxList顯示了最終的HTML生成,該方法定義如下。
方法RadioButtonCheckBoxList在生成RadioButtonList和CheckBoxList的時候才用<table>進行布局。組成RadioButtonList的單個RadioButton最終是調用HtmlHelper現有的擴充方法RadioButton生成的,而CheckBoxList中的CheckBox則是通過調用我們自定義的CheckBoxWithValue方法生成的。CheckBoxWithValue最終還是調用HtmlHelper現有的擴充方法CheckBox生成單個CheckBox對應的HTML,但是方法值支援布爾值的綁定,并且會生成一個在這裡不需要的Hidden元素,是以我們不得不在調用該方法的前後作一些手腳。
現在我們來介紹應用在Employee屬性上的四個特性的定義。如下面的代碼片斷所示,基于四種“清單控件”的特性均繼承自抽象特性ListAttribute。ListAttribute實作了IMetadataAware接口,在實作的OnMetadataCreated方法中将在構造函數中指定的代表清單名稱的ListName屬性添加到表示Model中繼資料的ModelMetadata對象的AdditionalValues屬性中。四個具體的清單特性重寫了OnMetadataCreated方法,并在此基礎上将ModelMetadata的TemplateHint分别設定為DropdownList、ListBox、RadioButtonList和CheckBoxList。
由于四個具體的ListAttribute已經對表示模闆名稱的ModelMetadata的TemplateHint進行了設定,那麼我們針對它們定義相應的分部View作為對應的模闆,那麼在調用HtmlHelper/HtmlHelper<TModel>相應模闆方法的時候就會按照這些模闆對目标元素進行呈現。實作如上圖所示的效果的四個模闆定義如下,它們被儲存在View\Shared\EditorTemplates目錄下面。
<a href="http://www.cnblogs.com/artech/archive/2012/05/02/model-metadata-and-template-01.html">ASP.NET MVC的Model中繼資料與Model模闆:預定義模闆</a>
<a href="http://www.cnblogs.com/artech/archive/2012/05/03/model-metadata-and-template-02.html">ASP.NET MVC的Model中繼資料與Model模闆:模闆的擷取與執行政策</a>
<a href="http://www.cnblogs.com/artech/archive/2012/05/04/model-metadata-and-template-03.html">ASP.NET MVC的Model中繼資料與Model模闆:将ListControl引入ASP.NET MVC</a>
作者:蔣金楠
微信公衆賬号:大内老A
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識别二維碼)關注個人公衆号(原來公衆帳号蔣金楠的自媒體将會停用)。
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。
<a href="http://www.cnblogs.com/artech/archive/2012/05/04/model-metadata-and-template-03.html" target="_blank">原文連結</a>