2010-08-01 63 views
9

我想扩展as​​p.net验证器,以便我可以使一个验证器依赖于另一个验证器。我的情况是,我们必须在文本框中验证日期。通常,我只是使用RequiredFieldValidator(确保提供日期),CompareValidator(确保日期是日期)和最后一个RangeValidator(确保日期在所需限制内)的组合。扩展ASP.NET验证器

这样做的问题是验证程序不相互依赖,因此,当我们真正希望他们看到的所有消息都是最相关的消息时,用户会立即看到每个验证程序的所有三条消息,即如果他们在日期文本框中输入“abc”,那么向他们显示消息说日期不在有效范围内(尽管技术上我认为这是真的)是不合适的。

当前为了提供这种功能,我们使用CustomValidator,并将所有三个验证放在服务器验证事件处理程序中,并根据验证失败以编程方式更改错误消息。

我想将这个标准化多一点,因为它在这个应用程序中发生了很多,我想我是否可以使验证器相互依赖,这将解决问题,并且还允许我们使用客户端而不必进行回发,特别是处理自定义验证。

这个想法是,如果一个验证器依赖另一个,如果该“主”是有效的,那么依赖将执行其正常验证(EvaluateIsValid()),否则如果主验证器无效,则其他依赖验证器将有效。

我已经通过继承已经在框架中提供的各种验证器控件提出了以下解决方案。

public class RequiredFieldDependentValidator : RequiredFieldValidator 
{ 
    [Description("The validation control to depend on for determining if validation should occur")] 
    public string ValidationControlToDependOn 
    { 
     get 
     { 
      object obj = ViewState["ValidationControlToDependOn"]; 
      if (obj != null) return (string) obj; 
      return null; 
     } 
     set 
     { 
      Control control = FindControl(value); 
      if (control is IValidator) 
       ViewState["ValidationControlToDependOn"] = value; 
      else 
       throw new HttpException("ValidationControlToDependOn is not a validation control"); 
     } 
    } 

    protected override bool EvaluateIsValid() 
    { 
     IValidator validationControlToDependOn = FindControl(ValidationControlToDependOn) as IValidator; 

     if(validationControlToDependOn != null) 
     { 
      return !validationControlToDependOn.IsValid || base.EvaluateIsValid(); 
     } 

     return base.EvaluateIsValid(); 
    } 

目前我刚刚编码它的RequiredFieldValidator的,最好我想所有的验证都提供了这种功能,但我看不到的方式来做到这一点而不复制上面的代码到每个类似的类验证器的个人类型我想提供此功能,因此如果有任何问题,我将不得不返回并单独更改每个验证器类型上的此代码。

有没有一种方法可以“集中”这段代码,并且可以很容易地在验证器中使用它,而无需从头开始编写整个验证器,以便我可以更改它们继承的类。

干杯,

回答

0

你可能想看看WebControlAdapter。

基本上可以让你重写webcontrols的某些方法(如果需要,有条件地适用于某些浏览器,但这里可以适用于所有方面)。

在你的情况,你会想重写EvaluateIsValid方法,并检查控件是否有任何依赖于'父'验证程序。

作为示例,我们最近创建了一个TextBox适配器,用于为控件呈现'maxlength'属性。

Public Class TextBoxAdapter 
     Inherits WebControlAdapter 

     Private ReadOnly Property TextBoxControl() As TextBox 
      Get 
       Return DirectCast(MyBase.Control, TextBox) 
      End Get 
     End Property 

     Protected Overrides Sub RenderBeginTag(ByVal writer As System.Web.UI.HtmlTextWriter) 
      If TextBoxControl.TextMode = TextBoxMode.MultiLine AndAlso TextBoxControl.MaxLength > 0 Then 
       writer.AddAttribute("maxlength", TextBoxControl.MaxLength.ToString) 
      End If 

      MyBase.RenderBeginTag(writer) 
     End Sub 
    End Class 

要使用它,只需在您的App_Browsers文件目录,并设置适配器有创建一个.browser文件:

<browsers> 
    <browser refID="Default"> 
     <controlAdapters> 
      <adapter controlType="System.Web.UI.WebControls.TextBox" 
       adapterType="TextBoxAdapter" /> 
     </controlAdapters> 
    </browser> 
</browsers> 

唯一的并发症,仍停留在你的情况是如何存储相关的验证以便EvaluateIsValid有权访问此目录。你可以考虑一个非呈现控件,比如Onof建议的或者Viewstate/Cookie /其他存储机制。

1

您可以覆盖您的页面库中的Validate方法。在页面中添加验证依赖信息,你可以实现一个没有渲染控制:

<my:ValidationDependency TargetControl="RegExp1" Dependency="Required1" /> 
0

你可以有ValidationControlToDependOn物业类型列表,并添加验证到列表中。所以我们可以假设稍后添加的验证器取决于之前添加的验证器。

所以你protected override bool EvaluateIsValid()

将改变有些

foreach(IValidator validator in ValidationControlToDependOn) 
{ 
return !validator.IsValid; 

} 
+0

不会让每个验证器在页面上依赖于前一个? 我想我仍然需要继承我试过的每个验证器 – 2010-08-01 07:25:54

0

我寻找到这似乎是它可能是有前途的控制扩展,但我无法找到做什么,但AJAX的东西与它的许多例子。

+0

,但是你不能覆盖扩展控件的方法。 IMO避免子类化的唯一方法是重写Page.Validate()。 – onof 2010-08-01 09:32:01