0

我似乎无法弄清楚如何验证将部分 ViewModel 作为子对象的 ViewModel 的部分视图片段。这是我最低级别的部分,它总是作为其他表单标签中的部分视图使用:

namespace MVC3App.ViewModels
{
    public class Payment : IValidatableObject
    {
        public decimal Amount { get; set; }
        public int CreditCardNumber { get; set; }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (Amount < 20)
                yield return new ValidationResult("Please pay more than $20", new string[] { "Amount" });
        }
    }
}

这是包含它的“主要”视图模型:

namespace MVC3App.ViewModels
{
    public class NewCustomerWithPayment :IValidatableObject
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public ViewModels.Payment PaymentInfo { get; set; }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (Age < 18)
                yield return new ValidationResult("Too young.", new string[] { "Age" });
        }
    }
}

对于 NewCustomerWithPayment 的视图,我有这个:

@model MVC3App.ViewModels.NewCustomerWithPayment
@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>NewCustomerWithPayment</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Age)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Age)
            @Html.ValidationMessageFor(model => model.Age)
        </div>
    </fieldset>
    @Html.Partial("Payment")
    <p><input type="submit" value="Create" /></p>
}

并且部分视图“付款”总是在另一个 Html.Beginform 标记中呈现,它只有这个:

@model MVC3App.ViewModels.Payment
<h2>Payment</h2>
<fieldset>
    <legend>Payment</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.Amount)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Amount)
        @Html.ValidationMessageFor(model => model.Amount)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.CreditCardNumber)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.CreditCardNumber)
        @Html.ValidationMessageFor(model => model.CreditCardNumber)
    </div>
</fieldset>

我的问题是我无法让“付款”视图模型上的验证工作。任何有使用 IValidatableObject 经验的人都可以在呈现为部分视图的 ViewModel 上加入并给我一个有效的验证模式吗?如果必须,我可以在没有 JavaScript 验证的情况下生活。

4

3 回答 3

1

这些答案都有一些很好的信息,但我的直接问题是通过使用这个来解决的:

@Html.EditorFor(model => model.PaymentInfo)

而不是这个:

Html.Partial("Payment", Model.PaymentInfo)

我很惊讶这有效,但确实有效。EditorFor 助手像 Html.Partial 一样渲染出局部视图,并自动连接到验证中。出于某种原因,它确实在子模型上调用了两次验证(在我的示例中为付款),这似乎是其他一些人报告的问题(http://mvcextensions.codeplex.com/workitem/10),所以我必须在每个模型上包含一个布尔值“HasBeenValidated”,并在 Validate 调用开始时检查它。

更新:您必须将视图移动到 /Views/Shared/ 下的 EditorTemplates 文件夹,以便 EditorFor 助手使用该视图。否则,EditorFor 将为您提供类型的默认编辑字段。

于 2012-09-17T13:37:02.047 回答
0

这是一个用于复选框的自定义验证器的蹩脚示例:) 我可能会编写一个自定义验证器或使用正则表达式。这可能会让你走上正确的道路并且更容易。

 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class CheckBoxMustBeTrueAttribute : ValidationAttribute, IClientValidatable
{
    #region IClientValidatable Members

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata,
                                                                           ControllerContext context)
    {
        yield return new ModelClientValidationRule
                         {
                             ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
                             ValidationType = "requiredcheckbox"
                         };
    }

    #endregion

    public override bool IsValid(object value)
    {
        if (value is bool)
        {
            return (bool) value;
        }
        return true;
    }
}
于 2012-09-14T20:06:54.063 回答
0

很可能IValidatableObject仅在根模型上被识别。Validate您可以从根模型调用内部模型方法:

public class NewCustomerWithPayment :IValidatableObject {
   ...
   public ViewModels.Payment PaymentInfo { get; set; }

   public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
   {
      if (Age < 18)
         yield return new ValidationResult("Too young.", new string[] { "Age" });

      if (this.PaymentInfo != null)
         yield return this.PaymentInfo.Validate(validationContext);
   }
}

注意:不确定上述是否编译。

于 2012-09-14T23:40:01.190 回答