Asp.net mvc 3 ASP.Net MVC 3-编辑器模板的客户端无干扰验证

Asp.net mvc 3 ASP.Net MVC 3-编辑器模板的客户端无干扰验证,asp.net-mvc-3,data-annotations,editortemplates,unobtrusive-validation,Asp.net Mvc 3,Data Annotations,Editortemplates,Unobtrusive Validation,我是ASP.NETMVC3新手,在尝试对我创建的用于以自定义方式显示日期的编辑器模板实施客户端不引人注目的验证时遇到了一些问题 UI 我需要以三个文本框的UI格式显示日期,如下所示 我已经建立了一个EditorTemplate,将日期显示为以下三个部分: @model DateTime? <table class="datetime"> <tr> <td>@Html.TextBox("Day", (Model.HasValue ? Model.V

我是ASP.NETMVC3新手,在尝试对我创建的用于以自定义方式显示日期的编辑器模板实施客户端不引人注目的验证时遇到了一些问题

UI
我需要以三个文本框的UI格式显示日期,如下所示


我已经建立了一个EditorTemplate,将日期显示为以下三个部分:

@model DateTime?

<table class="datetime">
<tr>
    <td>@Html.TextBox("Day", (Model.HasValue ? Model.Value.ToString("dd") : string.Empty)) </td>
    <td class="separator">/</td>
    <td>@Html.TextBox("Month", (Model.HasValue ? Model.Value.ToString("MM") : string.Empty))</td>
    <td class="separator">/</td>
    <td>@Html.TextBox("Year", (Model.HasValue ? Model.Value.ToString("yyyy") : string.Empty))</td>
</tr>
<tr>
    <td class="label">dd</td>
    <td/>
    <td class="label">mm</td>
    <td/>
    <td class="label">yyyy</td>
</tr>
</table>
客户端验证

我已经设置了一个自定义验证属性,该属性将IClientValidable实现为

public class DateTimeClientValidationAttribute : ValidationAttribute, IClientValidatable
{
    ...

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        List<ModelClientValidationRule> clientRules = new List<ModelClientValidationRule>();

        //Combined date should be valid
        ModelClientValidationRule validDateRule = new ModelClientValidationRule
        {
            ErrorMessage = "Please enter a valid date.",
            ValidationType = "validdate"
        };
        validDateRule.ValidationParameters.Add("dayelement", metadata.PropertyName + ".Day");
        validDateRule.ValidationParameters.Add("monthelement", metadata.PropertyName + ".Month");
        validDateRule.ValidationParameters.Add("yearelement", metadata.PropertyName + ".Year");
        clientRules.Add(validDateRule);

        return clientRules;
    }
    ...
}
公共类DateTimeClientValidationAttribute:ValidationAttribute,IClientValidatable
{
...
公共IEnumerable GetClientValidationRules(ModelMetadata元数据、ControllerContext上下文)
{
List clientRules=新列表();
//合并日期应有效
ModelClientValidationRule ValidTerule=新的ModelClientValidationRule
{
ErrorMessage=“请输入有效日期。”,
ValidationType=“validdate”
};
validDateRule.ValidationParameters.Add(“dayelement”,metadata.PropertyName+“.Day”);
validDateRule.ValidationParameters.Add(“monthelement”,metadata.PropertyName+“.Month”);
validDateRule.ValidationParameters.Add(“yearelement”,metadata.PropertyName+“.Year”);
clientRules.Add(validDateRule);
返回客户端规则;
}
...
}
我试图将这里的Day、Month和Year文本框的元素名称发送到客户端验证元素,以便稍后编写客户端jquery验证方法和适配器,它将使用这些元素并在客户端进行验证

查看
现在,为了使用这个编辑器模板,我将以下几行放在视图中

@model MyModel
...
<tr>
    <td class="editor-label">
        @Html.LabelFor(m => m.MySubModel.DateofBirth)
    </td>
    <td class="editor-field">
        @Html.EditorFor(m => m.MySubModel.DateofBirth)
        @Html.ValidationMessageFor(m => m.MySubModel.DateofBirth)
    </td>
</tr>
...
@model-MyModel
...
@LabelFor(m=>m.MySubModel.DateofBirth)
@EditorFor(m=>m.MySubModel.DateofBirth)
@Html.ValidationMessageFor(m=>m.MySubModel.DateofBirth)
...
在视图中添加所有相关jquery验证文件作为引用

问题

  • 虽然我已经实现了IClientValidable,但这并没有在html中发出不引人注目的javascript验证属性。 出于测试目的,当我将同一属性(DateTimeClientValidation)放在模型中未使用此编辑器模板的另一个属性上时,它发出了这些验证属性,而不是仅针对此编辑器模板发出。我哪里会出错
  • 关于编辑器模板的验证消息范围,我应该只将其放在视图中,还是直接放在编辑器模板中(@Html.ValidationMessageFor(m=>m.MySubModel.DateofBirth))
  • 在这个例子中,我的设计是对的,我加入了DateTimeClientValidationAttribute,这实际上是我在模型中加入的一个属性,但是这个组件对UI有一点了解(因为它试图向客户机输出Day、Month和Year元素名),这使模型对视图有一点了解,我是否违反了任何设计原则
  • 在DateTimeClientValidationAttribute中,我试图向客户机发出day、month和year元素名称,以便客户机脚本可以对其进行验证。但是,由于模型属性DateofBirth位于子对象中,脚本中的实际元素名称为MySubObject.DateofBirth,这使得Day文本框名称为MySubObject.DateofBirth.Day,如何在GetClientValidationRules方法中找到完全限定的模型名称,以便将名称发送给客户端

  • 感谢您耐心地阅读了所有这些内容,并给出了答案。好的,还有几件事。首先,如果可能的话,不要把日期分成三个字段。您只需将其设置为一个带有一些验证的单个字段,也许还有jQueryUI的DatePicker,就可以省去很多麻烦

    接下来,在DateTimeClientValidationAttribute中的自定义属性代码中,您永远不会通过实现IsValid来检查日期是否有效:

    protected override ValidationResult IsValid(object value, 
        ValidationContext validationContext) 
    {
       ...
       // Put date parts together and check is valid...
       if (DateTime.TryParse(year+"/"+month+"/"+day, out dateResult))
          return ValidationResult.Success;
    
       // Not valid
       return new ValidationResult(String.Format(ErrorMessageString, 
          validationContext.DisplayName));
    }
    
    接下来,您必须创建一个不引人注目的验证适配器和一个jQuery验证程序方法,该方法将参数放在一起,并尝试解析出日期:

    jQuery.validator.unobtrusive.adapters.add(
        'validdate', // notice this is coming from how you named your validation rule
        ['dayelement'],
        ['monthelement'],
        ['yearelement']
        function (options) {
            options.rules['datepartcheck'] = options.params;
            options.messages['datepartcheck'] = options.message;
        }
    );
    jQuery.validator.addMethod('datepartcheck', function (value, element, params) {
        var year = params[2];
        var month = params[1];
        var day = params[0];
    
        var birthDate = year + '/' + month-1 + '/' + day;
        var isValid = true;
    
        try {
            // datepicker is a part of jqueryUI.
            // include it and you can take advantage of .parseDate:
            $.datepicker.parseDate('yy/mm/dd', birthDate);
        }
        catch (error) {
            isValid = false;
        }
        return isValid;
    }, '');
    

    经过一番努力,我使控制发挥作用,如果它对任何人都有帮助的话

    第一点是将控件定义为

    @model DateTime?
    
    <table class="datetime">
    <tr>
        <td>@Html.TextBox("", (Model.HasValue ? Model.Value.ToString("dd") : string.Empty)) </td>
        <td class="separator">/</td>
        <td>@Html.TextBox("", (Model.HasValue ? Model.Value.ToString("MM") : string.Empty))</td>
        <td class="separator">/</td>
        <td>@Html.TextBox("", (Model.HasValue ? Model.Value.ToString("yyyy") : string.Empty))</td>
    </tr>
    <tr>
        <td class="label">dd</td>
        <td/>
        <td class="label">mm</td>
        <td/>
        <td class="label">yyyy</td>
    </tr>
    </table>
    
    @model DateTime?
    @text框(“,(Model.HasValue?Model.Value.ToString(“dd”):string.Empty))
    /
    @text框(“,(Model.HasValue?Model.Value.ToString(“MM”):string.Empty))
    /
    @Html.TextBox(“,(Model.HasValue?Model.Value.ToString(“yyy”):string.Empty))
    dd
    嗯
    年份
    
    确保将空字符串作为name赋给所有三个文本框,这将强制MVC框架为客户端的所有三个文本框生成与Model DateofBirth对应的相同name。此外,将为列表中的第一个文本框生成不引人注目的javascript验证参数,因为这是第一次出现具有模型名称的编辑控件

    在客户端,这些文本框上的任何事件都会触发所有相关的验证事件,因为所有这3个文本框都具有相同的名称


    在常规验证的基础上,如required,。。。。我们必须编写一个定制的客户端验证例程,该例程将组合所有这三个值,并检查组合值是否构成有效日期。这可以通过以下方式实现。

    我的客户要求促使我拆分日期控件。我不得不在jquery中使用一些不引人注目的管道&验证来让它工作,它现在正在工作,是的,正如你所说的,这是一个令人头痛的问题。您的答案是最接近的,因此请将其标记为答案。谢谢!我绞尽脑汁想弄明白那件事。
    @model DateTime?
    
    <table class="datetime">
    <tr>
        <td>@Html.TextBox("", (Model.HasValue ? Model.Value.ToString("dd") : string.Empty)) </td>
        <td class="separator">/</td>
        <td>@Html.TextBox("", (Model.HasValue ? Model.Value.ToString("MM") : string.Empty))</td>
        <td class="separator">/</td>
        <td>@Html.TextBox("", (Model.HasValue ? Model.Value.ToString("yyyy") : string.Empty))</td>
    </tr>
    <tr>
        <td class="label">dd</td>
        <td/>
        <td class="label">mm</td>
        <td/>
        <td class="label">yyyy</td>
    </tr>
    </table>