用于原始类型和向下转换的MVC3 Razor自定义模板

时间:2012-12-10 17:31:47

标签: c# asp.net-mvc-3 templates razor casting

我有一个视图模型:

public class AttributeEditorViewModel
{
    public long AttributeId { get; set; }
    public string DisplayName { get; set; }
    public object Value { get; set; }
}

使用模型构建器构建模型,以便最终视图模型具有上述对象的列表:

public class AttributeListViewModel
{
    public List<AttributeEditorViewModel> Attributes { get; set; }
}

我的模型构建器编译了一个AttributeEditorViewModel对象列表,并将相应的基元类型设置为Value属性。数据类型来自不同的属性定义。

现在Razor视图(比如edit.cshtml)看起来像:

@model AttributeListViewModel

@Html.EditorFor(m => m.Attributes)

和编辑器模板Views / Shared / EditorTemplates / AttributeEditorViewModel.cshtml:

@model AttributeEditorViewModel

<div>
    <label>@Model.DisplayName</label>
    @Html.EditorFor(m => m.Value)
    @Html.ValidationMessageFor(m => m.Value)
</div>

我期待的是什么;如果我将AttributeEditorViewModel的Value属性设置为double,如下所示:

public ActionResult Edit()
{
    return View(new AttributeListViewModel 
    {
        Attributes = new List<AttributeEditorViewModel> 
        {
            new AttributeEditorViewModel { DisplayName = "Double example", Value = (double) 0 }
        }
    };
}

我希望会呈现一个文本框。相反,它什么也没有呈现。我添加了另一个编辑器模板Views / Shared / EditorTemplates / Double.cshtml:

@model double

@Html.TextBoxFor(m => m)

这解决了眼前的问题。所以现在我得到一个值为0的文本框。但是,即使在自定义编辑器模板中使用EditorFor,也不会再渲染任何内容。

将对象用作基类型是否根本错误?为什么在使用EditorFor或EditorForModel时它什么都不渲染?

有任何见解。

3 个答案:

答案 0 :(得分:1)

这是因为EditorFor对泛型参数使用编译时绑定来确定要呈现的模板。

由于默认情况下没有定义EditorFor<object>(),所以什么也得不到。

如果您愿意,我相信您可以为对象定义自己的编辑器模板,但可能更好的方法是使您的视图模型通用:

public class AttributeEditorViewModel<TValue>
{
    public long AttributeId { get; set; }
    public string DisplayName { get; set; }
    public TValue Value { get; set; }
}

但是,这可能不太理想,因为您不再具有多态视图模型列表。

答案 1 :(得分:1)

对象和编辑器的问题正是你想要它做的,想象它包含2,000,000个DataTable的字典,每个DataTable包含300列和20,000行。它究竟应该显示什么?在模型上使用object类型的属性没有任何本质上的错误,只是不要指望Razor根据你在对象中的内容神奇地知道应该显示哪种编辑器。

答案 2 :(得分:1)

实际问题在于您的Razor视图代码。当你这样做时:

@Html.EditorFor(m => m.Attributes)

您告诉视图引擎为EditFor 寻找List<AttributeEditorViewModel>模板而不是 AttributeEditorViewModel。所以它使用默认的ObjectTemplate

[edit.chtml] 尝试类似:

@model AttributeListViewModel

@foreach (var att in Model.Attributes)
{
  @Html.EditorFor(m => att)
}

我不认为这个确切的答案会起作用(我不是在使用VS atm的机器上),但是它可以让你理解你遇到的问题。