2014年8月16日 星期六

ASP.NET MVC - 下拉選單的日期選擇器 Part.5 - Editor Templates

前一篇已經將一個相當陽春而且設定也不方便的 DateDropDownList 做了修改,在 Html Helper 裡透過 addtionalViewData 傳遞 DateDropDownList 的前端設定資料,如此一來在任何頁面裡都可以依據各自的需求用設定的方式來決定下拉選單日期選擇器的顯示內容。

不過前一篇的最後也提出了一個會遇到的情境,那就是假如網站裡所使用的下拉選單日期選擇器所顯示的樣式都是固定的,那麼是不是就要在每個有使用到的頁面裡,在 Html Helper 都要去加入 addtionalViewData 的設定呢?又或者就乾脆放棄 Part.4 的方法而直接使用 Part.3 的方法,然後再去 site.js 裡面直接去增加各種不同使用情境的顯示設定。

其實每一種作法都是可行的,不管是麻煩的、強調彈性的或是只想要簡單的,每種作法都有其適合的情境,不過還是強調一點,盡可能去尋找出最大的可能性,總是會有方法的。

 


在說明之前,先來看看 System.ComponentModel.DataAnnotations 命名空間,

MSDN - System.ComponentModel.DataAnnotations 命名空間

image

在這個命名空間裡提供了很多屬性類別,讓我們可以在模型類別裡去使用,在 Model 類別的屬性 ( Property ) 上面加註特定的 Attribute,用來定義屬性的特性與行為,例如用來作為資料的驗證。

我們也有在 DemoModel 有使用過 DataAnnotations 的屬性類別,例如:DataType, UIHint

image

image

 

不過這一篇要使用的並非是 System.ComponentModel.DataAnnotations 的屬性類別,而是在另一個命名空間的屬性類別。

MSDN - AdditionalMetadataAttribute 類別 (System.Web.Mvc)

SNAGHTML1d8074b

這是在 ASP.NET MVC 3 所新增加的類別,這個類別的屬性相當簡單,

image

在 Bruce Chen 的部落格裡「KingKong Bruce記事: ASP.NET MVC 3概觀正體中文版」這一篇文章就有對 AddtionalMetadataAttribute 類別作了說明,

你能使用 AdditionalMetadata 屬性對 Model 的一個屬性訪問 ModelMetadata.AdditionalValues 字典,例如,如果Model有一個屬性僅支援管理者顯示 …… 這個中繼資料(metadata)將被任何顯示或編輯樣板使用,這可讓你來解譯中繼資料(metadata)資訊。

而這就是我所想要的,因為我要做的事情就是在模型類別裡,針對特定的屬性(Property)去加註中繼資料,而這個中繼資料所要使用的 Attribute 類別並不是原本 System.ComponentModel.DataAnnotations 命名空間裡所提供的 Attribute 類別,就是使用 AddtionalMetadataAttribute 類別,讓我們可以加入名稱與值,然後再到 Editor Template 裡去取得並使用。

 

將 DemoModel 類別的 BirthDate 加註了幾個 AddtionalMetadataAttribute,並且設定名稱與值,

image

 

接著是要去修改 ~/Views/Shared/EditorTemplates 下的 DateDropDownList.cshtml 這個編輯範本,前面有說,因為是在 Model 類別裡加註使用 AdditionalMetadataAttribute,而在編輯範本裡就可以在 ViewData 的 ModelMetadata.AddtionalValues 取得放在 AdditionalMetadataAttribute 的資料,於是將 DateDropDownList.cshtml 的內容修改如下:

image

接著就是去使用這些資料,但是這邊必須要注意的是,我們在上一篇的修改裡已經是可以接受頁面裡 Html Helper 所給的 addtionalViewData,所以這邊不能夠以 AddtionalMetadataAttribute 的設定為優先。

應該說,我們在 Model 類別裡的 AddtionalMetadataAttribute 設定要視為一種預設值,當檢視頁面的 Html Helper 裡並沒有給設定資料的時候,就必須要使用 AddtionalMetadataAttribute 的設定,而如果 Html Helper 有給 addtionalViewData 資料時,那就是以 addtionalViewData 資料為優先使用。

image

完整的 DateDropDownList.cshtml 內容:

@model DateTime?
@{
    var value = Model.HasValue
                    ? Model.Value.ToString("yyyy-MM-dd")
                    : "";
                    
    var addtionalValues = ViewData.ModelMetadata.AdditionalValues;
    
    var options = ViewData.Keys
        .Where(item => item.StartsWith("_"))
        .ToDictionary(
            item => item.Substring(1), 
            item => ViewData[item]);
}
 
@Html.TextBox("", value, new
{
    @class = "form-control Date-DropDownList",
    data_TaiwanCalendarYear = options.ContainsKey("TaiwanCalendarYear")
        ? options["TaiwanCalendarYear"].Equals(true).ToString()
        : addtionalValues.ContainsKey("TaiwanCalendarYear")
            ? addtionalValues["TaiwanCalendarYear"].ToString() 
            : "False",
    data_YearStart = options.ContainsKey("YearStart")
        ? options["YearStart"]
        : addtionalValues.ContainsKey("YearStart")
            ? addtionalValues["YearStart"] 
            : DateTime.Now.AddYears(-100).Year,
    data_YearEnd = options.ContainsKey("YearEnd")
        ? options["YearEnd"]
        : addtionalValues.ContainsKey("YearEnd")
            ? addtionalValues["YearEnd"] 
            : DateTime.Now.Year,
    data_YearOption = options.ContainsKey("YearOption")
        ? options["YearOption"]
        : addtionalValues.ContainsKey("YearOption") 
            ? addtionalValues["YearOption"] 
            : string.Empty,
    data_MonthOption = options.ContainsKey("MonthOption")
        ? options["MonthOption"]
        : addtionalValues.ContainsKey("MonthOption") 
            ? addtionalValues["MonthOption"] 
            : string.Empty,
    data_DayOption = options.ContainsKey("DayOption")
        ? options["DayOption"]
        : addtionalValues.ContainsKey("DayOption")
            ? addtionalValues["DayOption"] 
            : string.Empty
})

 

執行

在 Sample1.cshtml 裡並沒有在 BirthDate 的 Html Helper 設定 additionalViewData,

image

DemoModel 類別

image

顯示結果

image

image

 

DemoModel 類別裡的 AdditionalMetadataAttribute 並不是六種都一定要設定,例如我將起迄年的設定給 comment 起來,然後以民國年來顯示(如果把 TaiwanCalendarYear 設定給拿掉,預設就是使用西元年),

image

顯示結果

image

image

 

如果將 DemoModel 類別裡的設定都完全恢復,然後在 Sample1.cshtml 裡 BirthDate 的 Html Helper 增加 additionalViewData 的資料,而且是給完全與 DemoModel 裡的設定截然不同的內容,

image

image

執行結果

image

image

 

如果兩邊(模型類別與檢視頁面)都不給設定資料的話,那麼就會是使用預設值,

image

image

 


在這一篇可以發現到完全沒有對已經完成功能設計的 site.js 做任何的修改,而是只有更改 DateDropDownList.cshtml 以及 DemoModel 類別的內容而已。

從第一篇看到第五篇,其實都沒有用到什麼太困難的技術或是結構,都是最基本的應用,每一篇都是一個階段一個階段的逐步改變與增強功能,將我們在專案裡區要使用到前端顯示從基本的作法開始做,最後變成可以獨立使用、也可以與模型類別結合使用,做成 Editor Templates 讓我們在開發網站時可以更為靈活使用。

這一個系列到這邊算是告一段落,很想在這篇就做一個結束,但是後來又想到,因為工作上所參與的一個專案,而這個專案對前端顯示的各個物件的組成有截然不同的作法,而那一種作法就是前面我有提到最不建議的「組合」方式,講組合是比較好聽,其實是「硬兜」而且是「義大利麵式」的作法,無論在使用上與維護上都是相當地有「討論空間」,並不是說這樣的作法就是一種錯的方式,只是我們必須要將這樣的做法給提出來做個探討。

 

參考連結與延伸閱讀

KingKong Bruce記事: ASP.NET MVC 3概觀正體中文版

ASP.NET MVC 3 で追加された AdditionalMetadata 属性を使う - しばやん雑記

Asp.Net MVC EditorTemplates/UIHint with parameters - Stack Overflow

Omar Venturi's Blog: How to pass parameters to ASP.NET MVC3 Razor EditorTemplates

ASP.NET MVC學習筆記(十一)-超好用的Templates - 我的Coding之路- 點部落

 

下一篇就繼續吧(有人已經覺得煩了嗎?

 

系列文章:

ASP.NET MVC - 下拉選單的日期選擇器 Part.1

ASP.NET MVC - 下拉選單的日期選擇器 Part.2

ASP.NET MVC - 下拉選單的日期選擇器 Part.3 - Editor Templates

ASP.NET MVC - 下拉選單的日期選擇器 Part.4 - Editor Templates

ASP.NET MVC - 下拉選單的日期選擇器 Part.5 - Editor Templates

ASP.NET MVC - 下拉選單的日期選擇器 Part.6 - @helper ?

ASP.NET MVC - 下拉選單的日期選擇器 part.7 - Validation

 

以上

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。