超好用的Templates

来源:互联网 发布:我国教育经费机制知 编辑:程序博客网 时间:2024/04/26 06:48

記得在一兩個月前我就寫過一篇初學ASP.NET MVC學習筆記(九)-Templates

但那時只是看看文章,順便紀錄一點學習心得而已,還沒體會到templates的用處

但最近因為專案做後台時大量的用到templates,才真正的覺得這真是個好東西

所以就來再一次的紀錄簡單的templates的運用

 

先建個簡單的table及dbml

image

然後建立一個 TemplateTB的 partial class,設定一點簡單的attribute

01[MetadataTypeAttribute(typeof(TemplateTBPartial))]
02public partial class TemplateTB
03{
04    private class TemplateTBPartial
05    {
06        public Guid ID { getset; }
07 
08        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")]
09        [DisplayName("選擇日期")]
10        [Required(ErrorMessage = "請選擇日期")]
11        public DateTime 日期 { getset; }
12 
13        [DisplayName("年齡")]
14        [Required(ErrorMessage = "請選擇年齡")]
15        public string 類別 { getset; }
16 
17        [DisplayName("性別")]
18        [Required(ErrorMessage = "請選擇性別")]
19        public bool 性別 { getset; }
20    }
21    partial void OnCreated()
22    {
23        _ID = Guid.NewGuid();
24    }
25}

首先先來解釋一下templates使用時的幾種方式

第一種:ASP.NET MVC內已有內建幾種預設的templates,例如 bool,EmailAddress,Url 等等等....

所以如果跟屬性型別一致,並在View上是用呼叫templates的Helper的話,就會自動以預設格式顯示

(View上怎麼以templates的方式叫用等等再說),也可以自己覆寫預設的格式。

第二種:C#裡面沒有Url這種型別,那要怎麼叫用預設的Url templates呢?這時只要在屬性上面加上

一個  [DataType(DataType.Url)] 的attribute,他就知道你要叫用Url的templates

第三種:如果預設的templates不夠我用,我希望自訂templates,並在partial class就指定這個屬性要用

哪個templates,該怎麼設定呢,也是在該屬性上加一句  [UIHint("自訂的templates名稱")] 就行了。

 

所以來改寫一下上面的partial class,我希望日期用Date這個templates,年齡用自訂的年齡選項templages

性別用預設的bool templates

01[DataType(DataType.Date)]
02[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")]
03[DisplayName("選擇日期")]
04[Required(ErrorMessage = "請選擇日期")]
05public DateTime 日期 { get; set; }
06 
07[UIHint("年齡選項")]
08[DisplayName("年齡")]
09[Required(ErrorMessage = "請選擇年齡")]
10public string 類別 { get; set; }
11 
12[DisplayName("性別")]
13[Required(ErrorMessage = "請選擇性別")]
14public bool 性別 { get; set; }

改完之後,開始實作自己的templates,首先要知道檔案要放哪

有兩種資料夾 DisplayTemplates 和 EditorTemplates

這兩個資料夾的名稱是不能改的。放置的位置跟Controller找view的方式很像

先找同名Controller資料夾下有沒有上面兩種templates資料夾,找不到的話再去Shared資料夾裡面找。

通常因為templates都是共用的,所以我習慣放在Shared裡面

image

image

建立完後,就可以開始在裡面寫要以甚麼樣的方式呈現這個templates囉。

首先先知道兩個常用的東西

ViewData.TemplateInfo.HtmlFieldPrefix  -- 代表使用這個templates的屬性名稱

ViewData.TemplateInfo.FormattedModelValue -- 屬性的值

有屬性名稱,有值,剩下UI的部分就可以靈活運用啦。

Shared\EditorTemplates\年齡選項.ascx

1<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
2<%ViewData[ViewData.TemplateInfo.HtmlFieldPrefix] = ViewData.TemplateInfo.FormattedModelValue;%>
3<%=Html.DropDownList("", DropDownListMenu.年齡選項(), "請選擇年齡")%>

第二行是利用MVC會自動把值帶入同欄位名稱的特性

所以先寫ViewData[欄位名稱]=值,之後如果下方有同樣欄位名稱的表單,就會自動把值帶入

第三行我希望這個templates可以用下拉選單的方式來呈現,所以我用了Html.DropDownList這個Helper

第一個參數是表單欄位名稱,給空值就好,因為它會自動加上去

第二個參數是傳入一個 IEnumerable<SelectListItem>,所以另外寫了一個class,以靜態的方法呼叫

第三個參數是預設的選項

接著來看這個靜態方法

01public static class DropDownListMenu
02{
03    public static IEnumerable<SelectListItem> 年齡選項()
04    {
05        List<SelectListItem> items = new List<SelectListItem>();
06        items.Add(new SelectListItem { Text = "0~20歲", Value = "0~20歲"});
07        items.Add(new SelectListItem { Text = "21~40歲", Value = "41~60歲" });
08        items.Add(new SelectListItem { Text = "61~80歲", Value = "61~80歲" });
09        items.Add(new SelectListItem { Text = "80歲以上", Value = "80歲以上" });
10        return items;
11    }
12 
13    public static string Show年齡選項(string s)
14    {
15      return 年齡選項()
16            .Where(p=>p.Value.Equals(s,StringComparison.CurrentCultureIgnoreCase))
17            .FirstOrDefault().Text;
18    }
19}

然後寫另外一個日期屬性的templates,因為我將他的DataType設為Data,因此我的templates取名為Date就行了

Shared\EditorTemplates\Date.ascx

1<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
2<script type="text/javascript">
3    $(function () {
4        $(".datepicker").datepicker({ "dateFormat""yy-mm-dd" })
5    });
6</script>
7<%=Html.TextBox("", String.Format("{0:yyyy-MM-dd}"
8, ViewData.TemplateInfo.FormattedModelValue), new { @class "datepicker" })%>

日期的部分我想用jQuery的datepicker的方式呈現,所以呢把該匯入的js檔跟css檔匯入

2-6行其實可以寫在masterpage裡面,但我為了清楚起見先寫在這裡

再來就是用Html.TextBox,幫他加一個class就好囉。

上面的兩個templates都是放在EditorTemplates裡面的,現在再建兩個templates放在DisplayTemplates裡

由於DisplayTemplates比較單純,我就直接貼Code了。

Shared\DisplayTemplates\Date.ascx

1<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
2<%=Html.Encode(String.Format("{0:yyyy-MM-dd}",ViewData.TemplateInfo.FormattedModelValue)) %>

Shared\DisplayTemplates\年齡選項.ascx

1<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
2<%=Html.Encode(DropDownListMenu.Show年齡選項(ViewData.TemplateInfo.FormattedModelValue.ToString()))%>

這樣Code的部分都寫完了,雖然寫了很多,但仔細想想這些東西都是可以重複利用十幾二十次,而且很好維護

的話,還是很划得來,剩下就是在View上怎麼去叫用了。

<%=Html.Display() %>                 --叫用DisplayTemplates裡面的templates 
<%=Html.DisplayFor() %>             --以強型別的方式叫用DisplayTemplates裡面的templates 
<%=Html.DisplayForModel() %>    --顯示整個Model

<%=Html.Editor() %>                   --叫用EditoerTemplates裡面的templates 
<%=Html.EditorFor() %>               --以強型別的方式叫用EditoerTemplates裡面的templates 
<%=Html.EditorForModel() %>      --編輯整個Model

各有三種寫法,但也可以說只有兩種,因為Display()跟DisplayFor()只是一種用強型別,一種不是而已。

DisplayForModel()是叫用整個class,如果想更改格式必須在資料夾底下建立同名的Partial View(例如

這個例子,名字就要取作 TemplateTB.ascx),這個我比較不常用到,所以還不是很熟悉。

那就直接來看看View的Code跟實際的畫面吧

Create.aspx跟Edit.aspx長的一樣

01<div class="editor-label">
02    <%= Html.LabelFor(model => model.日期) %>
03</div>
04<div class="editor-field">
05    <%= Html.EditorFor(model => model.日期)%>
06    <%= Html.ValidationMessageFor(model => model.日期,"", new { id = "Msg_日期" })%>
07</div>
08<div class="editor-label">
09    <%= Html.LabelFor(model => model.類別) %>
10</div>
11<div class="editor-field">
12    <%= Html.EditorFor(model => model.類別, new { id = "Msg_類別" })%>
13    <%= Html.ValidationMessageFor(model => model.類別, "", new { id = "Msg_類別" })%>
14</div>
15<div class="editor-label">
16    <%= Html.LabelFor(model => model.性別)%>
17</div>
18<div class="editor-field">
19    <%= Html.EditorFor(model => model.性別) %>
20    <%= Html.ValidationMessageFor(model => model.性別, "", new { id = "Msg_性別" })%>
21</div>

 

image

image image

 

 

附帶一提一個不相關的問題,如果屬性取中文名字,在Html.ValidationMessageFor()裡沒有另外加一個

id給他的話,就會出現下面的錯誤。

image

Details.aspx

1<div class="display-label">日期</div>
2<div class="display-field"><%= Html.DisplayFor(p=>p.日期) %></div>
3 
4<div class="display-label">類別</div>
5<div class="display-field"><%= Html.DisplayFor(p=>p.類別) %></div>
6 
7<div class="display-label">性別</div>
8<div class="display-field"><%= Html.DisplayFor(p => p.性別)%></div>

image

 

Html.DisplayFor()跟Html.EditorFor()共有六種呼叫方法

其中有一個參數 string templateName,是可以在特殊情況下,你希望這個屬性用其他的templates的話,

可以使用這個參數傳入templates名稱,如

1<%= Html.EditorFor(model => model.類別,"指定其他的Templates")%>

這樣一來,這個屬性就不會去用原先設定的 "年齡選項"的templates,改用"指定其他的Templates"這個名稱

的templates來顯示。

 

另外一個參數 object additionalViewData,是可以傳入其他資訊,如

1<%= Html.EditorFor(model => model.類別, new { 附加條件="Test" })%>

這樣的話,在templates內就可以用 ViewData["附加條件"] , 抓到 Test這個值。

 

還有一個參數是 string htmlFieldName,是可以改變表單欄位名稱的,例如

1<%= Html.EditorFor(model => model.類別,"指定其他的Templates","xxx")%>

這樣在"指定其他的Templates" 這個templates中,用ViewData.TemplateInfo.HtmlFieldPrefix抓出來的

值就會變成 xxx

 

 

 

呼,寫了好多。整篇文章可能有點雜亂,因為除了templates之外,還加入了我自己實作的部分

但我只是想強調templates有多好用,像是日期,性別這種簡單的東西之外,還可以把連動式的縣市選單

,或是上傳檔案的按鈕做成tempaltes的話,以後要用時只要在partial class上加個屬性就搞定了。

 

Tony Stark說好的武器只要發射一次,所以好的Code應該也只要寫一次,然後重複利用才是。



http://www.dotblogs.com.tw/lastsecret/archive/2010/07/11/16486.aspx