ASP.NET MVC的Model中繼資料與Model模板:模板的擷取與執行策略

來源:互聯網
上載者:User

當我們調用HtmlHelper或者HtmlHelper<TModel>的模板方法對整個Model或者Model的某個資料成員以某種模式(顯示模式或者編輯模式)進行呈現的時候,通過預先建立的代表Model中繼資料的ModelMetadata對象都可以找到相應的模板。如果模板對應著某個自訂的分部View,那麼只需要執行該View即可;對於預設範本,則直接可以得到相應的HTML。本篇文章著重討論模板的擷取和執行機制,不過在這之前,順便來討論一下DataTypeAttribute和模板的關係。

一、 DataTypeAttribute和模板有何關係?

通過《初識Model中繼資料》針對Model中繼資料定義的介紹,我們知道通過DataTypeAttribute特性對目標元素設定的資料類型最終會反映在表示Model中繼資料的ModelMetadata對象的DataTypeName屬性上。此外,對於某些設定的資料類型,比如Date、Time、Duration和Currency等,還會隨之建立一個DisplayFormatAttribute應用到ModelMetadata上。那麼ModelMetadata的DataTypeName屬性對目標元素的最終呈現具有怎樣的影響呢?

實際上在模板匹配的過程中會將ModelMetadata的DataTypeName屬性當作模板名稱來看待,所以下面兩種形式的Model類型定義可以看成是等效的。通過UIHintAttribute特性設定的模板名稱和通過DataTypeAttribute特性設定的資料類型的唯一不同之處在於前者具有更高的優先順序。換句話說,如果將UIHintAttribute和DataTypeAttribute同時應用到同一個資料成員分別將模板名稱和資料類型設定為ABC和123,自訂模板123隻有在模板ABC不存在的情況下才會被使用。

   1: public class Model
2: {
3: [DataType(DataType.Html)]
4: public string Foo { get; set; }
5:
6: [DataType(DataType.MultilineText)]
7: public string Bar { get; set; }
8:
9: [DataType(DataType.Url)]
10: public string Baz { get; set; }
11: }
12:
13: public class Model
14: {
15: [UIHint("Html")]
16: public string Foo { get; set; }
17:
18: [UIHint("MultilineText")]
19: public string Bar { get; set; }
20:
21: [UIHint("Url")]
22: public string Baz { get; set; }
23: }

執行個體示範:證明DataTypeName與模板名稱的等效性

為了證明通過DataTypeAttribute特性設定資料類型在針對目標元素進行可視化呈現過程中被視為模板名稱,我們來做一個簡單的執行個體示範。在這個執行個體中我們定義了如下一個表示三角形的資料類型Triangle,其屬性A、B和C是一個Point對象,表示三個角所在的座標。

   1: public class Triangle
2: {
3: [DataType("PointInfo")]
4: public Point A { get; set; }
5:
6: [DataType("PointInfo")]
7: public Point B { get; set; }
8:
9: [DataType("PointInfo")]
10: public Point C { get; set; }
11: }
12:
13: [TypeConverter(typeof(PointTypeConverter))]
14: public class Point
15: {
16: public double X { get; set; }
17: public double Y { get; set; }
18: public Point(double x, double y)
19: {
20: this.X = x;
21: this.Y = y;
22: }
23:
24: public static Point Parse(string point)
25: {
26: string[] split = point.Split(',');
27: if (split.Length != 2)
28: {
29: throw new FormatException("Invalid point expression.");
30: }
31: double x;
32: double y;
33: if (!double.TryParse(split[0], out x) ||!double.TryParse(split[1], out y))
34: {
35: throw new FormatException("Invalid point expression.");
36: }
37: return new Point(x, y);
38: }
39: }
40:
41: public class PointTypeConverter : TypeConverter
42: {
43: public override bool CanConvertFrom(ITypeDescriptorContext context,Type sourceType)
44: {
45: return sourceType == typeof(string);
46: }
47:
48: public override object ConvertFrom(ITypeDescriptorContext context,CultureInfo culture, object value)
49: {
50: if (value is string)
51: {
52: return Point.Parse(value as string);
53: }
54: return base.ConvertFrom(context, culture, value);
55: }
56: }

對於類型Triangle和Point的定義,有兩點值得注意:其一,Triangle的三個A、B和C屬性上應用了DataTypeAttribute特性並將自訂資料類型設定為PointInfo(不是Point);其二,Point類型上應用了TypeConverterAttribute特性並將TypeConverter類型設定為PointTypeConverter,後者支援源自字串的類型轉換。通過前面對複雜類型(Complex Type)的介紹,這樣會將Triangle的三個屬性從複雜類型成員轉換成簡單類型成員。根據前提介紹的關於Object模板對資料成員的便利規則,Triangle的這三個屬性才能被最終呈現出來。

現在我們建立一個Model類型為Point的強型別分部View作為模板,並將其命名為PointInfo(和前面通過DataTypeAttribute特性指定的自訂資料類型一致)。我們只為Point定義關於顯示模式的模板,所以我們將該分部View檔案放在Views\Shared\DisplayTemplates中。如下面的代碼片斷所示,我們將一個Point對象顯示為(X,Y)的形式。

   1: @model MvcApp.Models.Point
2: (@Model.X, @Model.Y)

現在我們建立一個預設的HomeCtroller。如下面的代碼片斷所示,在預設的Index操作方法中我們建立了一個Triangle對象將其呈現在預設的View中。

   1: public class HomeController : Controller
2: {
3: public ActionResult Index()
4: {
5: Triangle triangle = new Triangle
6: {
7: A = new Point(1,2),
8: B = new Point(2,3),
9: C = new Point(3,4)
10: };
11: return View(triangle);
12: }
13: }

下面是對應的View的定義,這是一個Model類型為Triangle的強型別View,我們僅僅調用了HtmlHelper<TModel>的DisplayModel方法將作為Model的Triangle對象以顯示模式呈現出來。

   1: @model MvcApp.Models.Triangle
2: @Html.DisplayForModel()

運行該Web應用會在瀏覽器中得到如下圖所示的呈現效果,我們可以看到作為我們建立的Triangle對象的A、B和C屬性工作表示的三個角的座標是完全按照我們定義的PointInfo模板的方式進行呈現的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.