2010-10-24 75 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,所以也许将来有可能取代反射代码。