6

我正在使用 DataAnnotations 编写一个 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>

现在,我的问题是Bar 的内部模板我想从我的 model 访问另一个属性。我不想为 FooModel 创建单独的模板,因为我将不得不对所有其他 FooModel 属性进行硬编码。

在使用调试器进行简短调查后,我可以看到:

  1. this.ViewData.ModelMetadata.ContainerTypeFooModel(如预期的那样)
  2. this.ViewData.TemplateInfo有一个非公共属性VisitedObjects (类型为 System.Collections.Generic.HashSet<object>),其中包含两个元素: FooModelDateTime?

如何访问我的 FooModel?我不想使用反射来破解我的方式。

更新:

我已经接受了 mootinator 的回答,因为它在我看来是允许类型安全的最佳解决方案。我也赞成 Tx3 的答案,因为 mootinator 的答案建立在它之上。尽管如此,我认为在这些场景中应该有更好的 MVC 支持,我认为这在现实世界中很常见,但在示例应用程序中却没有。

4

5 回答 5

3

也许您可以创建新类,比如说 UserDateTime,它将包含可为空的 DateTime 和您需要的其余信息。然后,您将为 UserDateTime 使用自定义显示模板并访问您需要的信息。

我意识到您可能正在寻找其他类型的解决方案。

于 2011-02-15T13:16:51.473 回答
2

我认为您最好将此功能提取到父视图中的 HtmlHelper 调用。

类似的东西RenderSpecialDateTime<TModel>(this HtmlHelper html, Expression<Func<TModel,DateTime?>> getPropertyExpression)可能会完成这项工作。

否则,您将不得不执行 Tx3 建议的操作。我赞成他的回答,但将其发布为替代方案。

于 2011-02-18T02:24:44.440 回答
1

您不能在控制器中使用 ViewData 字典对象,然后在 ViewUserControl 中获取它吗?它不会是强类型的,但是......如果它是空的,你可以编写一个助手来不做任何事情,如果它有一个值,则链接到示例登录历史页面。

于 2011-02-15T22:26:11.913 回答
1

似乎在 MVC 5.0 和 5.2.2 之间的某个地方,在 ModelMetadata 类中添加了一个“Container”属性。

但是,由于负责元数据创建的提供程序中的所有方法(GetMetadataForProperty、Create 等)的签名中都没有容器,因此仅在某些情况下(根据反射代码的 GetMetadataForProperties 和 GetMetadataFromProvider)分配 Container 属性,在我的情况下通常为空。

所以我最终做的是在一个新的元数据提供者中覆盖 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 正在纠正这个过度的问题,所以将来可能会替换反射代码。

于 2015-01-20T23:57:56.373 回答
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>>因此,您不必在任何地方明确命名要使用的模板。这更像是事情的工作方式。

于 2011-02-21T18:46:01.837 回答