ASP.NET MVC 學習筆記(十三)-自訂DataAnnotationsModelMetadataProvider讓UIHint在MVC中可以傳遞參數

將近一年前,寫過一篇 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方法

01public class ExtendDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
02{
03    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
04    {
05        //不希望覆寫太多東西,所以大部分還是用base的CreateMetadata方法
06        ModelMetadata metadata = base.CreateMetadata(attributes,
07                                                      containerType,
08                                                      modelAccessor,
09                                                      modelType,
10                                                      propertyName);
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));
15        //如果有UIHint屬性,就將他的參數塞到ModelMetadata.AdditionalValues裡面
16        //Key是UIHintTemplateControlParameters
17        if (uiHintAttribute != null)
18        {
19            if (metadata.AdditionalValues.ContainsKey("UIHintTemplateControlParameters"))
20                throw new ArgumentException("Metadate.AdditionalValues已存在 \"UIHintTemplateControlParameters\"這個Key,請更換擴充UIHintAttribute的Key值。");
21            metadata.AdditionalValues.Add("UIHintTemplateControlParameters", uiHintAttribute.ControlParameters);
22        }
23        return metadata;
24    }
25}


第二步:

在MVC中的 Globol.asax 的 Application_Start中,指定 ModelMetadataProviders

1protected void Application_Start()
2{
3    AreaRegistration.RegisterAllAreas();
4    RegisterRoutes(RouteTable.Routes);
5    ModelMetadataProviders.Current = new ExtendDataAnnotationsModelMetadataProvider();
6}

 

使用方式:

先定義自己的Model,並套上要使用的屬性

01public class TestModel
02{
03    public string Name { get; set; }
04    //第一個參數是指定templates名稱,如果要依型別找templates的話可以不填
05    //第二個參數是表示用在哪,這邊可以填MVC或不填
06    //第三個參數之後就是自訂的參數,用key/value的方式
07    //一個key,一個value的方式依序傳遞
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; }
14}

 

 

 

覆寫預設的Templates

image

String.ascx

1<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
2  
3<%
4    var txtWidth = Html.GetUIHintParametersValue<int>("Width");
5    txtWidth = txtWidth == 0 ? 100 : txtWidth;
6    var color = Html.GetUIHintParametersValue<string>("Color","blue");
7%>
8  
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" %>
2  
3<% var dateFormat = Html.GetUIHintParametersValue<string>("DateFormat", "yyyy-MM-dd"); %>
4  
5<%=Html.TextBox("", String.Format("{0:"+dateFormat+"}", ViewData.TemplateInfo.FormattedModelValue), new { @class = "datepicker" })%>

 

String.ascx這個Template還是出現一個TextBox,但可以設定寬度及顏色

DateTime.ascx則是加入了jQuery的datepicker,並且可以設定日期的format

另外為了方便抓出存在metadata中的參數,我另外寫了一個Helper來使用

01public static class UIHientHelper
02{
03    /// <summary>
04    /// 擴充HtmlHelper
05    /// 如果ModelMetadata.AdditionalValues中有UIHintTemplateControlParameters這個Key,就回傳Dictionary
06    /// </summary>
07    public static Dictionary<string, object> GetUIHintParametersDictionary(this HtmlHelper helper)
08    {
09        var additionalValues = helper.ViewContext.ViewData.ModelMetadata.AdditionalValues;
10        if (additionalValues.ContainsKey("UIHintTemplateControlParameters"))
11        {
12            Dictionary<string, object> dic = (Dictionary<string, object>)additionalValues["UIHintTemplateControlParameters"];
13            return dic;
14        }
15        return null;
16    }
17    /// <summary>
18    /// 擴充HtmlHelper
19    /// 用指定的key去抓設定在UIHintTemplateControlParameters Dictionary中的Value
20    /// </summary>
21    public static T GetUIHintParametersValue<T>(this HtmlHelper helper,string key)
22    {
23        return GetUIHintParametersValue<T>(helper,key,default(T));
24    }
25    /// <summary>
26    /// 擴充HtmlHelper
27    /// 用指定的key去抓設定在UIHintTemplateControlParameters Dictionary中的Value
28    /// 並在沒有設定時傳回預設值
29    /// </summary>
30    public static T GetUIHintParametersValue<T>(this HtmlHelper helper, string key, T defaultValue)
31    {
32        var dic = GetUIHintParametersDictionary(helper);
33        if (dic != null && dic.ContainsKey(key))
34        {
35            var value = dic[key].ToConvertOrDefault<T>(defaultValue);
36            return value;
37        }
38        return defaultValue;
39    }
40}

擴充object,一個小小的型別轉換器

01public static T ToConvertOrDefault<T>(this object obj, T defaultValue)
02{
03    try
04    {
05        return (T)Convert.ChangeType(obj, typeof(T));
06    }
07    catch
08    {
09        return defaultValue;
10    }
11}

 

測試結果

Controller

01public ActionResult Index()
02{
03    TestModel model = new TestModel()
04    {
05        Name = "CodingRoad",
06        Age = "26",
07        Birthday = new DateTime(1985, 6, 28, 12, 5, 0),
08        WeddingDate = new DateTime(2013, 1, 4)
09    };
10    return View(model);
11}

View

01<%=Html.LabelFor(p => p.Name)%>:<%=Html.EditorFor(p=>p.Name) %>
02<br />
03<br />
04<br />
05<%=Html.LabelFor(p=>p.Age) %>:<%=Html.EditorFor(p=>p.Age) %>
06<br />
07<br />
08<br />
09<%=Html.LabelFor(p=>p.Birthday) %>:<%=Html.EditorFor(p=>p.Birthday) %>
10<br />
11<br />
12<br />
13<%=Html.LabelFor(p => p.WeddingDate)%>:<%=Html.EditorFor(p=>p.WeddingDate) %>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值