將近一年前,寫過一篇 ASP.NET MVC學習筆記(十一)-超好用的Templates
那時候就覺得 MVC 的 Templates 功能非常的好用,但在MVC中用 UIHint屬性 選擇樣板的時候
無法傳遞參數,讓Templates的使用上會多了一點限制。
(在Dynamic Data中,UIHint是可以傳遞參數的,但在MVC的預設Provider沒有支援,只能使用ViewData傳遞)
最近剛好跟朋友又在討論這個問題,搜尋了一下發現已經有人分享出解決辦法了。
參考網址:Using UIHint With ControlParameters in MVC
所以自己就照著這個概念實作了自己的版本,以後當成自己的 Library 使用。
p.s 如果還不清楚 mvc 的 templates 要怎麼使用,請先看一下我之前的文章會比較清楚這篇在講什麼
第一步:
繼承 DataAnnotationsModelMetadataProvider 類別,
自訂一個自己的Provider,然後override CreateMetadata方法
01 | public class ExtendDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider |
03 | protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func< object > modelAccessor, Type modelType, string propertyName) |
06 | ModelMetadata metadata = base .CreateMetadata(attributes, |
11 | List<Attribute> attributeList = new List<Attribute>(attributes); |
12 | IEnumerable<UIHintAttribute> uiHintAttributes = attributeList.OfType<UIHintAttribute>(); |
13 | UIHintAttribute uiHintAttribute = uiHintAttributes.FirstOrDefault(a => String.Equals(a.PresentationLayer, "MVC" , StringComparison.OrdinalIgnoreCase)) |
14 | ?? uiHintAttributes.FirstOrDefault(a => String.IsNullOrEmpty(a.PresentationLayer)); |
17 | if (uiHintAttribute != null ) |
19 | if (metadata.AdditionalValues.ContainsKey( "UIHintTemplateControlParameters" )) |
20 | throw new ArgumentException( "Metadate.AdditionalValues已存在 \"UIHintTemplateControlParameters\"這個Key,請更換擴充UIHintAttribute的Key值。" ); |
21 | metadata.AdditionalValues.Add( "UIHintTemplateControlParameters" , uiHintAttribute.ControlParameters); |
第二步:
在MVC中的 Globol.asax 的 Application_Start中,指定 ModelMetadataProviders
1 | protected void Application_Start() |
3 | AreaRegistration.RegisterAllAreas(); |
4 | RegisterRoutes(RouteTable.Routes); |
5 | ModelMetadataProviders.Current = new ExtendDataAnnotationsModelMetadataProvider(); |
使用方式:
先定義自己的Model,並套上要使用的屬性
03 | public string Name { get ; set ; } |
08 | [UIHint( "" , "MVC" , "Width" , 25, "Color" , "red" )] |
09 | public string Age { get ; set ; } |
10 | [UIHint( "DateTime" , "MVC" , new Object[] { "DateFormat" , "yyyy-MM-dd HH:mm:ss" })] |
11 | public DateTime Birthday { get ; set ; } |
12 | [DisplayName( "結婚紀念日" )] |
13 | public DateTime WeddingDate { get ; set ; } |
覆寫預設的Templates

String.ascx
1 | <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> |
4 | var txtWidth = Html.GetUIHintParametersValue< int >("Width"); |
5 | txtWidth = txtWidth == 0 ? 100 : txtWidth; |
6 | var color = Html.GetUIHintParametersValue< string >("Color","blue"); |
9 | <%=Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { style=String.Format("width:{0}px;color:{1}",txtWidth,color) })%> |
DateTime.ascx
1 | <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> |
3 | <% var dateFormat = Html.GetUIHintParametersValue< string >("DateFormat", "yyyy-MM-dd"); %> |
5 | <%=Html.TextBox("", String.Format("{0:"+dateFormat+"}", ViewData.TemplateInfo.FormattedModelValue), new { @class = "datepicker" })%> |
String.ascx這個Template還是出現一個TextBox,但可以設定寬度及顏色
DateTime.ascx則是加入了jQuery的datepicker,並且可以設定日期的format
另外為了方便抓出存在metadata中的參數,我另外寫了一個Helper來使用
01 | public static class UIHientHelper |
05 | /// 如果ModelMetadata.AdditionalValues中有UIHintTemplateControlParameters這個Key,就回傳Dictionary |
07 | public static Dictionary< string , object > GetUIHintParametersDictionary( this HtmlHelper helper) |
09 | var additionalValues = helper.ViewContext.ViewData.ModelMetadata.AdditionalValues; |
10 | if (additionalValues.ContainsKey( "UIHintTemplateControlParameters" )) |
12 | Dictionary< string , object > dic = (Dictionary< string , object >)additionalValues[ "UIHintTemplateControlParameters" ]; |
19 | /// 用指定的key去抓設定在UIHintTemplateControlParameters Dictionary中的Value |
21 | public static T GetUIHintParametersValue<T>( this HtmlHelper helper, string key) |
23 | return GetUIHintParametersValue<T>(helper,key, default (T)); |
27 | /// 用指定的key去抓設定在UIHintTemplateControlParameters Dictionary中的Value |
30 | public static T GetUIHintParametersValue<T>( this HtmlHelper helper, string key, T defaultValue) |
32 | var dic = GetUIHintParametersDictionary(helper); |
33 | if (dic != null && dic.ContainsKey(key)) |
35 | var value = dic[key].ToConvertOrDefault<T>(defaultValue); |
擴充object,一個小小的型別轉換器
01 | public static T ToConvertOrDefault<T>( this object obj, T defaultValue) |
05 | return (T)Convert.ChangeType(obj, typeof (T)); |
測試結果
Controller
01 | public ActionResult Index() |
03 | TestModel model = new TestModel() |
07 | Birthday = new DateTime(1985, 6, 28, 12, 5, 0), |
08 | WeddingDate = new DateTime(2013, 1, 4) |
View
01 | <%=Html.LabelFor(p => p.Name)%>:<%=Html.EditorFor(p=>p.Name) %> |
05 | <%=Html.LabelFor(p=>p.Age) %>:<%=Html.EditorFor(p=>p.Age) %> |
09 | <%=Html.LabelFor(p=>p.Birthday) %>:<%=Html.EditorFor(p=>p.Birthday) %> |
13 | <%=Html.LabelFor(p => p.WeddingDate)%>:<%=Html.EditorFor(p=>p.WeddingDate) %> |