让我们从我们所知道的开始:
正如描述所暗示的,如果我们有我们的模型:
A型:
public class A
{
public B ModelB { get; set; }
}
B型:
public class B : IValidatableObject
{
public string Name { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
List<ValidationResult> errors = new List<ValidationResult>();
if (string.IsNullOrEmpty(Name)) {
errors.Add(new ValidationResult("Please enter your name"));
}
return errors;
}
}
而我们的观点:
@model A
@Html.ValidationSummary(true)
@using (Html.BeginForm())
{
@Html.EditorFor(model => model.ModelB.Name)
<input type="submit" value="submit" />
}
然后编辑器将输出该行:
<input class="text-box single-line" id="ModelB_Name" name="ModelB.Name" type="text" value="" />
如果我们将post 操作定义为:
[HttpPost]
public ActionResult Index(A model)
{
if (ModelState.IsValid)
{
return RedirectToAction("NextAction");
}
return View();
}
然后在绑定到A
模型时,DefaultModelBinder
将查找命名的属性ModelB.Name
,它将找到并成功绑定到该属性。
DefaultModelBinder
但是,针对模型执行的模型验证A
将调用为 Model 定义的验证B
。此验证将返回未针对属性定义的错误消息,但由于此验证是复杂模型的一部分,因此它使用“ModelB”键添加到 ModelState。
当ValidationSummary
调用它时,它会查找空白的键(即为模型而不是属性定义的)。由于不存在空白键,因此不会显示错误。
作为一个简单的解决方法,您可以EditorTemplate
为B
模型定义一个。
在包含您的视图的文件夹中,定义一个名为的文件夹EditorTemplates
,并在其中创建一个与模型同名的视图(例如B.cshtml
在我的例子中)。编辑器模板的内容将定义为:
@model MvcApplication14.Models.B
@Html.EditorFor(m => m.Name)
然后,修改主视图,使其EditorFor
如下所示:
@Html.EditorFor(model => model.ModelB, null, "")
"" 指定我们的编辑器模板输出的任何字段都不会在字段前加上名称。因此,现在的输出将是:
<input class="text-box single-line" id="Name" name="Name" type="text" value="" />
但是,这现在将阻止绑定,ModelB
因此需要在 post 操作中单独绑定并添加到我们的A
模型中:
[HttpPost]
public ActionResult Index(A modelA, B modelB)
{
modelA.ModelB = modelB;
if (ModelState.IsValid)
{
return RedirectToAction("NextAction");
}
return View();
}
现在,当modelB
绑定时,验证消息将ModelState
使用键“”写入。因此,现在可以使用@ValidationMessage()
例程来显示它。
警告:上述变通方法假定modelB
不具有与 相同的字段名称modelA
。modelB
例如,如果两者modelA
都有一个Name
字段,则DefaultModelBinder
可能无法将字段绑定到其正确的等效项。例如,如果A
模型还有一个名为的字段Name
,则必须将其写入视图:
@Html.EditorFor(model => model.Name, null, "modelA.Name")
以确保正确绑定。
希望这应该允许您使用已在 MVC3 框架中定义的方法来实现所需的结果。