2010-10-24 50 views
6

我正在使用DataAnnotations編寫MVC2應用程序。我有以下型號:MVC2 - 如何獲取模板內的父模型(容器)

public class FooModel 
{ 
    [ScaffoldColumn("false")] 
    public long FooId { get; set; } 

    [UIHint("BarTemplate")] 
    public DateTime? Bar { get; set;} 
} 

我想爲Bar創建一個自定義顯示模板。我已經創建了下面的模板:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<DateTime?>" %> 

<div class="display-label"> 
    <span><%: Html.LabelForModel() %></span> 
</div> 
<div class="display-field"> 
    <span><%: Html.DisplayForModel()%></span> 
    <%: Html.ActionLink("Some link", "Action", new { id = ??FooId?? }) %> 
</div> 

現在,我的問題是,內模板吧我想從我的模型訪問其他財產。我不想爲FooModel創建單獨的模板,因爲我不得不硬編碼所有其他FooModel屬性。

與調試簡短的調查後,我可以看到:

  1. this.ViewData.ModelMetadata.ContainerTypeFooModel(預期)
  2. this.ViewData.TemplateInfo有 非公共財產 (類型 System.Collections.Generic.HashSet<object>VisitedObjects 其中包含兩個元素: FooModelDateTime?

我該如何訪問我的FooModel?我不想破解我使用Reflection的方式。

更新:

我已經接受mootinator的答案,因爲它看起來對我來說是允許類型安全的最佳解決方案。我也提出了Tx3的答案,因爲mootinator的答案是建立在答案上的。儘管如此,我認爲在那些場景中應該有更好的MVC支持形式,我認爲這在現實世界中很常見,但在示例應用程序中卻很少見。

+0

@Jakub:Bar.cshtml的模型是'DateTime?'的類型,沒有'm.Bar'我認爲。 – xport 2011-02-15 10:54:43

+0

@Recycle Bin - 乾杯,編輯了這個問題。 – 2011-02-15 11:20:44

+0

@Jakub:我不明白爲什麼你需要從'DateTime?'內訪問'FooModel'。它沒有任何意義。 :-) – xport 2011-02-15 11:25:32

回答

0

對不起,如果這個建議看起來很愚蠢,我還沒有嘗試過,但你不能做什麼Tx3建議,而不必創建一堆新類,通過定義一個泛型類來引用你想要的任何父類型?

public class FooModel 
    { 
     [ScaffoldColumn("false")] 
     public long FooId { get; set; } 

     [UIHint("BarTemplate")] 
     public ParentedDateTime<FooModel> Bar { get; set;} 

     public FooModel() 
     { 
      Bar = new ParentedDateTime<FooModel>(this); 
     } 
    } 


    public class ParentedDateTime<T> 
    { 
     public T Parent {get; set;} 
     public DateTime? Babar {get; set; } 

     public ParentedDateTime(T parent) 
     { 
      Parent = parent; 
     } 

} 

你可以展開封裝任何舊類型與類型通用一個<Parent, Child>,甚至。

這也給你,你強類型的模板將是

Inherits="System.Web.Mvc.ViewUserControl<ParentedDateTime<FooType>>這樣你就不必在任何地方使用的模板顯式名稱的好處。這是更多的東西是如何工作的。

+0

您可以更進一步並創建ParentedField 。你需要1個類,但是你的模型仍然是'醜陋的',因爲FooModel屬性的類型是ParentedField 等。它仍然爲我着迷。我的觀點是,ModelMetadata已經有了我的父對象 - 我不想「監視」我的模型(圖像在序列化爲JSON時的樣子,我也這樣做)。 – 2011-02-21 22:07:47

+0

@Jakub我可能只是爲JSON保留一個單獨的ViewModel。如果可能的話,我可以明白爲什麼你想避免重複。 – 2011-02-21 22:35:02

+0

專門用於完成所需內容的語法仍涉及使用ViewData:http://www.dalsoft.co.uk/blog/index.php/2010/07/29/asp-net-mvc-2-template-助手 - 讓 - 你到指定-額外視圖數據/ – 2011-02-21 22:54:54

3

也許你可以創建新的類,比如說UserDateTime,它將包含可爲空的DateTime和你需要的其他信息。然後,您將使用UserDateTime的自定義顯示模板並訪問您所需的信息。

我意識到您可能正在尋找其他類型的解決方案。

+0

這將意味着改變我的UserDetailsModel,我不願意這樣做。我應該有5個DateTime屬性,我將不得不繼續創建不同的類並複製數據。我的觀點是:我的模型中已經有了我需要的數據。不管怎麼說,還是要謝謝你! – 2011-02-15 13:22:40

+0

好點。我也很想聽聽解決方案。 – Tx3 2011-02-15 13:44:04

1

難道你不能在控制器中使用ViewData字典對象,然後在ViewUserControl中抓取?它不會被強類型化,但是......如果它是空的,你可以編寫一個幫手來不做任何事情,並且如果有示例登錄歷史記錄頁面,則鏈接到它。

+0

我不想複製數據。我已經在我的模型中使用了它,並且我不想將我的一半模型放入ViewData。 – 2011-02-15 22:28:03

+0

而不是嘗試混合和匹配,將模型填充到ViewData中,然後在控件中將其拉出。 – Webjedi 2011-02-15 22:29:21

+0

ViewData不安全。我非常重視類型安全。 – 2011-02-18 06:19:53

2

我想你可能會更好地從父視圖中提取HtmlHelper調用此功能。

類似RenderSpecialDateTime<TModel>(this HtmlHelper html, Expression<Func<TModel,DateTime?>> getPropertyExpression)可能會完成這項工作。

否則,你將不得不做一些像Tx3建議的事情。我提出了他的答案,但將其作爲替代方案發布。

+0

對不起,我不明白。 1)提取*什麼*功能? 2)當我在父視圖中做的所有事情都是Html.DisplayForModel()時,我應該如何在父視圖中調用Html.RenderSpecialDateTime()? – 2011-02-18 06:17:53

1

它會出現MVC 5.0和5.2.2之間的一個「容器」屬性添加到ModelMetadata類。但是,因爲負責創建元數據(GetMetadataForProperty,Create等)的提供者中的所有方法在其簽名中都沒有容器,所以僅在某些情況下才會分配Container屬性(根據反射代碼,GetMetadataForProperties和GetMetadataFromProvider)在我的情況下通常是空的。

所以我最後做的是重寫GetMetadataForProperty在新的元數據提供者,並將其設置有:

public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName) 
{ 
    var propMetaData = base.GetMetadataForProperty(modelAccessor, containerType, propertyName); 
    Object container = modelAccessor.Target.GetType().GetField("container").GetValue(modelAccessor.Target); 
    propMetaData.Container = container; 
    return propMetaData; 
} 

我知道這是反射,但它是相當簡潔。這似乎是MS正在糾正這個oversiteite,所以也許將來有可能取代反射代碼。