ASP.NET MVC 3 部分视图模板

4
坦白说,我不知道该如何称呼这个问题或者如何开始搜索它。
我有一个标准布局的显示页面。
<div>
    <label for="field">Field Name:</label>
    @Model.Field
</div>

为了使其更易于更改,我希望制作一个模板,而不是使用上面的代码逐个输入每个字段。

我创建了一个包含以下内容的部分视图:

@model System.Object
<div>
    @Html.LabelFor(m => m)
    @Html.DisplayFor(m => m)
</div>

在我的视图中,我添加了以下内容:

@Html.Partial("_BillField", Model.Field)

该模型随后具有如下描述:
public ModelName {
    [Display(Name="Field Description")]
    public decimal Field { get; set; }
}

当在主视图中时,这个功能可以工作,但使用模板时标签却缺失了。我错过了什么吗?
更新:根据@K. Bob的建议,我对局部视图进行了修改。
<div>
    @Html.LabelFor(m => m)
    @Html.DisplayFor(m => m)
</div>

更新2:为了让大家更加清楚我想要的内容。

最终,我希望能够做到以下几点:

@Html.Partial("_BillField", Model.Field1)
@Html.Partial("_BillField", Model.Field2)
@Html.Partial("_BillField", Model.Field3)

并且具有相当于以下内容的功能:

<div>
    <label for="field1">Field 1 Name:</label>
    @Model.Field1
</div>
<div>
    <label for="field2">Field 2 Name:</label>
    @Model.Field2
</div>
<div>
    <label for="field3">Field 3 Name:</label>
    @Model.Field3
</div>

很抱歉之前没有表述清楚。


请注意,LabelFor等的参数不是Func,而是Expression<Func>。这是因为它可以使用反射来访问模型成员(即其值、类型、名称和属性,例如DisplayName)。当您直接将模型成员传递到部分时,您正在更改该表达式,因此它无法再在原地访问该成员,只能访问该成员的类型和值,因为它缺少模型的上下文。 - jpaugh
你可能需要一个自定义模型绑定器或模型绑定器模板,尽管我没有使用过它们。 - jpaugh
5个回答

2

如果你不在局部视图中指定 @model,它会使用其父级 @model。如果你将局部视图中的 @model 移除,能否解决问题?

如果我的视图是这样的...

@model MyApp.Models.ModelName
@{
    ViewBag.Title = "Test";
}

<h2>Test</h2>
<div>
           <div class="editor-label">
                @Html.LabelFor(m => m.Field)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(m => m.Field)
                @Html.ValidationMessageFor(m => m.Field)
            </div>
</div>
@Html.Partial("_partial", Model) @*note I pass the whole model*@

And this as the partial....

@model MyApp.Models.ModelName
<div>
              <div class="editor-label">
                @Html.LabelFor(m => m.Field)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(m => m.Field)
                @Html.ValidationMessageFor(m => m.Field)
            </div>
</div>

然后它会执行我认为你想要做的事情(显然,它会执行两次,但是你可以从主视图中删除代码)。 但我不确定它会给你带来很大的好处。也许我误解了什么。


没有,它没有。修正问题以反映更改。 - Mike Wills
@Mike - 当你调用 @Html.Partial("_BillField", Model.Field) 时,它只传递了 Field 属性的值,而不是整个带有数据注释属性的 Field 属性(如果你明白我的意思的话)。 - K. Bob
@MikeWills - 我已经更新了我的答案,并提供了一个可行的示例,所以忽略关于此示例未声明模型的部分。如果您传递一个值(例如Model.Field),则不需要模型。 - K. Bob
但我想要一个通用的东西,可以重复使用。这样我就可以只做 @Html.Partial("_BillField", Model.Field) @Html.Partial("_BillField", Model.Field2) @Html.Partial("_BillField", Model.Field3) 等等。我也会将其添加到问题中。 - Mike Wills
@MikeWills - 你是在寻找一个HTMLHelper,它可以生成其他HTMLHelpers的聚合HTML,是吗?你只需要给它模型,而不必编写三个“块”Helper代码,只需编写一个?如果这正是你要寻找的,请提出一个新问题。 - K. Bob


1

你不需要对你的属性使用ToString()方法。

@Html.LabelFor(m => m)

更新

根据您想要做的事情,重用视图,请看一下我写的关于验证和部分视图重用的比普通文章更长的帖子,它是ASP.NET MVC 3 - Model Validation答案的一部分。非常详细。


糟糕,复制粘贴出了问题。我在发布之前忘记删除ToString(),导致页面崩溃了。这个问题已经在原始帖子中得到修复。 - Mike Wills

1

我认为你应该考虑使用显示/编辑模板来处理类型,因为你的模型包含了3个该类型的字段。

@Html.Partial("_BillField", Model.Field1)
@Html.Partial("_BillField", Model.Field2)
@Html.Partial("_BillField", Model.Field3)

相对于部分视图,为类型定义模板可能更加有效。请参见ASP.NET MVC 3 - Partial vs Display Template vs Editor Template以获取详细比较。

在这种情况下,您的视图将更像:

@Html.DisplayFor(model => model.Field1)
@Html.DisplayFor(model => model.Field2)
@Html.DisplayFor(model => model.Field3)

你的模型将会是:

public class model
{
   [DisplayName("Field1")]
   public ComplexType Field1 {get;set;}
   [DisplayName("Field2")]
   public ComplexType Field2 {get;set;}
   [DisplayName("Field3")]
   public ComplexType Field3 {get;set;}
}

或者是用于显示名称的数据注释。


1
我决定不再按照自己的想法去做,但这可能是最好的解决方案。 - Mike Wills

0

在澄清问题后,添加了一个新答案,因为另一个答案没有回答问题。 这篇文章 LabelFor extension 应该能够根据您的需求进行调整,但最好不要覆盖,而是创建自己的扩展。

您需要以略微不同的方式调用它,因为您需要使用 m=>m.Field 语法。但我相信这应该可以满足您的需求,而无需使用部分视图。

如果您使用 Model.Field 语法,您只会发送 Field 属性的实际值,例如您的十进制数值 1.23,您需要使用 m=>m.Field 来获取更多属性的计算结果,以便您可以更改标签中的文本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接