我有一个MVC3页面与对象(头),有数据,我想在一个页面上更新对象(详细信息)的列表。 在详细信息对象我有自定义的验证(IValidatableObject)也需要运行。
这似乎通常工作正常,验证正在运行和返回ValidationResults,如果我把一个@ Html.ValidationSummary(假); 在页面上会显示这些验证。 不过,我不希望在顶部验证的列表,而是该项目旁边被验证即Html.ValidationMessageFor这是在页面上,但不显示相关的提示信息。 是否有什么我失踪? 这是在其他网页上(即没有这个主 - 详细情况),所以我想这是一些关于我如何去有关设置要更新的项目列表或编辑模板的项目?
Edit.cshtml(页眉-详细编辑视图)
@foreach (var d in Model.Details.OrderBy(d => d.DetailId))
{
@Html.EditorFor(item => d, "Detail")
}
Detail.ascx(详细信息编辑模板)
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Detail>" %>
<tr>
<td>
<%= Model.Name %>
<%= Html.HiddenFor(model => model.DetailId) %>
</td>
<td class="colDescription">
<%= Html.EditorFor(model => model.Description) %>
<%= Html.ValidationMessageFor(model => model.Description) %>
</td>
<td class="colAmount">
<%= Html.EditorFor(model => model.Amount) %>
<%= Html.ValidationMessageFor(model => model.Amount) %>
</td>
</tr>
型号是实体框架与具有名称和HeaderId和细节都DetailId,HeaderId,说明和金额标题
控制器代码:
public ActionResult Edit(Header header, FormCollection formCollection)
{
if (formCollection["saveButton"] != null)
{
header = this.ProcessFormCollectionHeader(header, formCollection);
if (ModelState.IsValid)
{
return new RedirectResult("~/saveNotification");
}
else
{
return View("Edit", header);
}
}
else
{
return View("Edit", header);
}
}
[我知道控制器代码可以作为尝试,以确定哪些是这里存在的一个结果被清理了一下,就在这个状态]
IValidatableObject实现:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (this.Name.Length < 5) && (this.Amount > 10))
{
yield return new ValidationResult("Item must have sensible name to have Amount larger than 10.", new[] { "Amount" });
}
}
我会建议你使用真正的编辑模板。 与您的代码的问题是,你写你的视图内foreach循环来呈现它产生相应的输入字段错误名称的模板。 我想这就是为什么你在你的控制器动作来填充模型做了一些变通的理由( header = this.ProcessFormCollectionHeader(header, formCollection);
),而不是简单地使用模型绑定来完成这项工作。
因此,让我告诉你正确的方法来实现这一目标。
模型:
public class Header
{
public IEnumerable<Detail> Details { get; set; }
}
public class Detail : IValidatableObject
{
public int DetailId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int Amount { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if ((this.Name ?? string.Empty).Length < 5 && this.Amount > 10)
{
yield return new ValidationResult(
"Item must have sensible name to have Amount larger than 10.",
new[] { "Amount" }
);
}
}
}
控制器:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new Header
{
Details = Enumerable.Range(1, 5).Select(x => new Detail
{
DetailId = x,
Name = "n" + x,
Amount = 50
}).OrderBy(d => d.DetailId)
};
return View(model);
}
[HttpPost]
public ActionResult Index(Header model)
{
if (ModelState.IsValid)
{
return Redirect("~/saveNotification");
}
return View(model);
}
}
视图( ~/Views/Home/Index.cshtml
):
@model Header
@using (Html.BeginForm())
{
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
@Html.EditorFor(x => x.Details)
</tbody>
</table>
<button type="submit">OK</button>
}
为详细类型编辑器模板( ~/Views/Shared/EditorTemplates/Detail.ascx
或~/Views/Shared/EditorTemplates/Detail.cshtml
为剃刀):
<%@ Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<MvcApplication1.Controllers.Detail>"
%>
<tr>
<td>
<%= Html.DisplayFor(model => model.Name) %>
<%= Html.HiddenFor(model => model.DetailId) %>
<%= Html.HiddenFor(model => model.Name) %>
</td>
<td class="colDescription">
<%= Html.EditorFor(model => model.Description) %>
<%= Html.ValidationMessageFor(model => model.Description) %>
</td>
<td class="colAmount">
<%= Html.EditorFor(model => model.Amount) %>
<%= Html.ValidationMessageFor(model => model.Amount) %>
</td>
</tr>
这里有两件事是我完善你的代码:
- 我在控制器级别进行的详细集合排序由DetailId。 这是控制器的责任准备视图模型显示。 认为不应该做这种排序。 所有这一切的观点应该做的是显示数据
- 由于先前的改善我的git摆脱在视图中的foreach循环您正在使用渲染编辑模板,并用单取代它
@Html.EditorFor(x => x.Details)
调用。 其工作原理是,ASP.NET MVC检测Details
是(类型的集合属性IEnumerable<Detail>
),它会自动寻找内部模板的自定义编辑~/Views/SomeController/EditorTemplates
或~/Views/Shared/EditorTemplates
夹称为Detail.ascx
或Detail.cshtml
(相同的名称作为收集的类型)。 然后,它会呈现此模板收集的每一个元素,让你不必担心 - 由于以前的改善,内部
[HttpPost]
行动不再需要任何ProcessFormCollectionHeader
黑客。 的header
操作参数将被从请求数据由模型粘合剂正确绑定 - 内部的
Detail.ascx
模板我已经取代<%= Model.Name %>
与<%= Html.DisplayFor(model => model.Name) %>
为了正确HTML编码输出和填充XSS孔,其是开放的在您的网站。 - 里面的
Validate
方法,我保证, Name
属性不是针对它的长度在测试前空。 通过在你的榜样你的方式只有一个输入字段在模板中的描述字段,并没有对相应的输入字段Name
属性,因此在提交表单时,该属性将始终为空。 因此我添加了一个相应的隐藏输入字段它。