好的,我会努力让你完成 90% 的路程。这实际上是 MVC 2 的一个巨大而复杂的部分,仅在这个答案框中几乎不可能回答。
现在首先您应该访问 Brad Wilsons 博客并深入阅读如何自定义默认 MVC 2 模板。这应该让您更清楚地了解所有活动部件。
http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html
现在我将开始一个简单的示例,说明如何创建一个人为的约会视图模型,我们希望确保提供的值不会及时返回。现在不要关注属性,我们会到达那里。
这是我正在使用的 ViewModel:
public class AppointmentViewModel
{
[Required]
public string Name { get; set; }
[CantGoBackwardsInTime]
public DateRange DateRange { get; set; }
}
public class DateRange
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
[Required]
public int Price { get; set; }
}
我已经将它添加到默认的 HomeController 中(没什么花哨的):
public ActionResult Appointment()
{
return View(new AppointmentViewModel());
}
[HttpPost]
public ActionResult Appointment(AppointmentViewModel appointment)
{
return View(appointment);
}
这是我的观点:
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Appointment
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Add Appointment</h2>
<%= Html.ValidationSummary() %>
<% using( Html.BeginForm()) { %>
<%= Html.EditorForModel() %>
<input type="submit" value="Save Changes" />
<%} %>
</asp:Content>
第 1 步:搭建舞台
您要做的第一件事是从博客条目中获取“默认模板”。在这种情况下,重要的是位于 /Views/Shared/EditorTemplates/Object.asxc 中的那个 Object.ascx 是整个操作的基石。所有 Html.Editor***** 方法最终都会调用它。
现在我们必须更改的第一条默认功能是 Object.ascx 中的这一行
<% if (ViewData.TemplateInfo.TemplateDepth > 1) { %>
<%= ViewData.ModelMetadata.SimpleDisplayText%>
<% }
这就是“不显示任何嵌套的复杂类型”,我们不希望这样。将 > 1 更改为 > 2。现在,对象图中的视图模型将为它们创建模板,而不仅仅是创建占位符文本。
暂时保持其他一切默认即可。
*第 2 步:覆盖模板**
如果您阅读了博客条目,希望您现在了解 Editor*** 和 Display 方法将如何自动调用 View/Shared/EditorTemplates 和 DisplayTemplates 中的模板。把它们想象成调用 Html.RenderPartial("TYPENAME", MyType ) 他们不是但在概念上足够接近。
因此,如果您运行该解决方案并转到正确的 url,您会注意到 MVC 2 将调用 Object.ascx 两次,一次用于您的 AppointmentViewModel,另一次用于属性 DateRange。开箱即用只是呈现相同的表单字段集合。
假设我们想让我们的模板用一个红色边框包围我们的 DateRange 编辑器。我们想要做的是短路 MVC 2 来调用自定义 DateTime.ascx 模板而不是 Object.ascx,这就像在 View/Shared/EditorTemplates/DateRange.ascx 中添加我们自己的模板一样简单。在这种情况下,我刚刚将 Object.ascx 生成的内容与我们的 DateRange 模型一起使用,并将代码粘贴到新的 DateRange.ascx 中:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<div style="border: 1px solid #900">
<div class="editor-label"><label for="DateRange">DateRange</label></div>
<div class="editor-field">
<div class="editor-label"><label for="DateRange_Start">Start</label>
</div>
<div class="editor-field">
<input class="text-box single-line" id="DateRange_Start" name="DateRange.Start" type="text" value="" />
</div>
<div class="editor-label"><label for="DateRange_End">End</label></div>
<div class="editor-field">
<input class="text-box single-line" id="DateRange_End" name="DateRange.End" type="text" value="" />
</div>
<div class="editor-label"><label for="DateRange_Price">Price</label></div>
<div class="editor-field">
<input class="text-box single-line" id="DateRange_Price" name="DateRange.Price" type="text" value="" />
</div>
</div>
</div>
哇!
现在,当您运行解决方案时,您应该会在 DateRange 周围看到一个红色框。其余的自定义由您决定!您可以添加 jQuery 日期选择器框。在您的情况下,您可以将两个字段放在一个 div 中,以便它们水平排列。在这一点上,天空是极限。
第 3 步:验证:
验证的工作方式与您期望的差不多。您的 [Required] 属性
DateRange 类型的工作方式与任何其他验证属性相同。
现在你看到我在 AppointmentViewModel 的 DateRange 属性上设置了一个不能倒退的时间属性。要创建这些特定于类型的验证属性,您所要做的就是继承并实现基本的 ValidationAttribute:
public class CantGoBackwardsInTime : ValidationAttribute
{
public override string FormatErrorMessage(string name)
{
return "Your date range can't go backwards in time";
//return base.FormatErrorMessage(name);
}
public override bool IsValid(object value)
{
if (!(value is DateRange))
throw new InvalidOperationException("This attributes can only be used on DateRange types!");
var dateRange = value as DateRange;
return dateRange.End > dateRange.Start;
}
}
现在,如果您添加它并装饰您的属性,您应该会看到自定义 CantGoBackwardsInTime 验证属性中提供的错误消息。
如果您有任何问题,我会更新并清理更多内容,但这应该可以帮助您开始并继续前进。 (以为我可以在睡觉前把它搞定)只是一个警告:MVC 2 片段的新编辑器是世界上最棒的东西,并且有巨大的潜力赋予 MVC 2 超级 RAD 功能;然而,除了 Brad Wilson 的博客之外,几乎没有什么可了解的信息。只要坚持下去,如果你也需要,不要害怕偷看 MVC 2 源代码。