Base Validator Control Sample

The base validator control described here implements the steps described in Developing a Validator Control. The client-side scripting provided by this base validator complies with the World Wide Web Consortium Document Object Model Level 1 specification.

To compile and build this sample, see the instructions in Validator Control Samples. For an overview of client-side scripting in server controls, see Client-Side Functionality in a Server Control.

// BaseDomValidator.cs.
namespace DomValidators {

    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing;
    using System.Globalization;
    using System;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.HtmlControls;
    using System.Text.RegularExpressions;
    using System.Text;

    [
    DefaultProperty("ErrorMessage"),
    ]
    public abstract class BaseDomValidator : Label, IValidator {

        // Note: these script-enabled controls have two sets
        // of client-side script. 
        // There is a fixed set in a script library called 
        // DomValidation.js. This goes at the top of the page
        // and is put on the page using RegisterClientScriptBlock.
        // The second is the dynamic block 
        // below that contains some inline script that 
        // should be executed at the end of the page load.
        // This is declared using RegisterStartupScript.

        private const string ValidatorFileName = "DomValidation.js";
        private const string ValidatorIncludeScriptKey = "DomValidatorIncludeScript";
        private const string ValidatorStartupScript = @"
<script language=""javascript"">
<!--

var Page_ValidationActive = false;
if (typeof(Page_DomValidationVer) == ""undefined"")
    alert(""{0}"");
else
    ValidatorOnLoad();

function ValidatorOnSubmit() {{
    if (Page_ValidationActive) {{
        return ValidatorCommonOnSubmit();
    }}
}}

// -->
</script>
        ";
        private const string IncludeScriptFormat = @"
<script language=""{0}"" src=""{1}{2}""></script>";

        private bool preRenderCalled;
        private bool isValid;
        private bool propertiesChecked;
        private bool propertiesValid;
        private bool renderUplevel;

        protected BaseDomValidator() {
            isValid = true;
            propertiesChecked = false;
            propertiesValid = true;
            renderUplevel = false;

            // Default forecolor for validators is Red.
            ForeColor = Color.Red;
        }

        [
        DefaultValue(typeof(Color), "Red")
        ]
        public override Color ForeColor {
            get {
                return base.ForeColor;
            }
            set {
                base.ForeColor = value;
            }
        }        

        [
        Category("Behavior"),
        DefaultValue(""),
        Description("The control to validate."),
        TypeConverter(typeof(ValidatedControlConverter))
        ]                                         
        public string ControlToValidate {
            get { 
                object o = ViewState["ControlToValidate"];
                return((o == null) ? String.Empty : (string)o);
            }
            set {
                ViewState["ControlToValidate"] = value;
            }
        }

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("Error Message")
        ]
        public string ErrorMessage {
            get {
                object o = ViewState["ErrorMessage"];
                return((o == null) ? String.Empty : (string)o);
            }
            set {
                ViewState["ErrorMessage"] = value;
            }
        }

        [
        Category("Behavior"),
        DefaultValue(true),
        Description("Enable Client Script")
        ]
        public bool EnableClientScript {
            get {
                object o = ViewState["EnableClientScript"];
                return((o == null) ? true : (bool)o);
            }
            set {
                ViewState["EnableClientScript"] = value;
            }
        }

        public override bool Enabled {
            get {
                return base.Enabled;
            }
            set {
                base.Enabled= value;
                // When a validator is disabled, 
                // generally, the intent is not to
                // make the page invalid for that round trip.
                if (!value) {
                    isValid = true;
                }
            }
        }        

        [
        Browsable(false),
        Category("Behavior"),
        DefaultValue(true),
        Description("Is Valid"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public bool IsValid {
            get {
                return isValid;
            }
            set {
                isValid = value;
            }
        }

        protected bool PropertiesValid {
            get {
                if (!propertiesChecked) {
                    propertiesValid = ControlPropertiesValid();
                    propertiesChecked = true;
                }
                return propertiesValid;
            }
        }

        protected bool RenderUplevel {
            get {
                return renderUplevel;
            }
        }

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(ValidatorDisplay.Static),
        Description("Display"),
        ]
        public ValidatorDisplay Display {
            get {
                object o = ViewState["Display"];
                return((o == null) ? ValidatorDisplay.Static : (ValidatorDisplay)o);
            }
            set {
                if (value < ValidatorDisplay.None || value > ValidatorDisplay.Dynamic) {
                    throw new ArgumentException();
                }
                ViewState["Display"] = value;
            }
        }

        protected override void AddAttributesToRender(HtmlTextWriter writer) {
            // Validators do not render the disabled attribute; 
            // instead, they are invisible when they are disabled.
            bool disabled = !Enabled;
            if (disabled) {
                Enabled = true;
            }
            base.AddAttributesToRender(writer);

            if (RenderUplevel) {
                // A validator must have an ID on the client, 
                // so if it is null, write it here.
                // Otherwise, base.RenderAttributes takes care of it.
                if (ID == null) {
                    writer.AddAttribute("id", ClientID);
                }

                if (ControlToValidate.Length > 0) {
                    writer.AddAttribute("controltovalidate", GetControlRenderID(ControlToValidate));
                }
                if (ErrorMessage.Length > 0) {
                    writer.AddAttribute("errormessage", ErrorMessage, true);
                }
                ValidatorDisplay display = Display;
                if (display != ValidatorDisplay.Static) {
                    writer.AddAttribute("display", PropertyConverter.EnumToString(typeof(ValidatorDisplay), display));
                }
                if (!IsValid) {
                    writer.AddAttribute("isvalid", "False");
                }
                if (disabled) {
                    writer.AddAttribute("enabled", "False");
                }
            }
            if (disabled) {
                Enabled = false;
            }
        }

        protected void CheckControlValidationProperty(string name, string propertyName) {
            // Get the control using the relative name.
            Control c = NamingContainer.FindControl(name);            
            if (c == null) {
                throw new HttpException("Control not found.");
            }

            // Get  the control's validation property.
            PropertyDescriptor prop = GetValidationProperty(c);
            if (prop == null) {
                throw new HttpException("Control cannot be validated.");                          
            }

        }

        protected virtual bool ControlPropertiesValid() {
            // Determine whether the control to validate is blank.
            string controlToValidate = ControlToValidate;
            if (controlToValidate.Length == 0) {
                throw new HttpException("ControlToValidate cannot be blank.");
            }

            // Check that the property points to a valid control
            // (if not, an exception is thrown). 
           
            CheckControlValidationProperty(controlToValidate, "ControlToValidate");

            return true;
        }                     

        protected abstract bool EvaluateIsValid();    

        protected string GetControlRenderID(string name) {

            // Get the control using the relative name.
            Control c = FindControl(name);            
            if (c == null) {
                Debug.Fail("We should have already checked for the presence of this");
                return "";
            }
            return c.ClientID;
        }


        protected string GetControlValidationValue(string name) {

            // Get the control using the relative name.
            Control c = NamingContainer.FindControl(name);            
            if (c == null) {
                return null;
            }

            // Get the control's validation property.
            PropertyDescriptor prop = GetValidationProperty(c);
            if (prop == null) {
                return null;
            }

            // Get its value as a string.
            object value = prop.GetValue(c);
            if (value is ListItem) {
                return((ListItem) value).Value;
            }
            else if (value != null) {
                return value.ToString();
            }
            else {
                return string.Empty;
            }
        }                

        public static PropertyDescriptor GetValidationProperty(object component) {
            ValidationPropertyAttribute valProp = (ValidationPropertyAttribute)TypeDescriptor.GetAttributes(component)[typeof(ValidationPropertyAttribute)];
            if (valProp != null && valProp.Name != null) {
                return TypeDescriptor.GetProperties(component, null)[valProp.Name];
            }
            return null;
        }

        protected override void OnInit(EventArgs e) {
            base.OnInit(e);
            Page.Validators.Add(this);
        }        

        protected override void OnUnload(EventArgs e) {
            if (Page != null) {
                Page.Validators.Remove(this);
            }
            base.OnUnload(e);
        }        

        protected override void OnPreRender(EventArgs e) {
            base.OnPreRender(e);
            preRenderCalled = true;

            // Force a re-query of properties for render.
            propertiesChecked = false;                       

            // Work out uplevelness now.
            renderUplevel = DetermineRenderUplevel();

            if (renderUplevel) {
                RegisterValidatorCommonScript();
            }
        }

        protected virtual bool DetermineRenderUplevel() {

            // Must be on a page.
            Page page = Page;
            if (page == null || page.Request == null) {
                return false;
            }

            // Check the browser capabilities. 
            // This is how you can get automatic fallback to server-side 
            // behavior. These validation controls need 
            // the W3C DOM level 1 for control manipulation
            // and need at least ECMAScript 1.2 for the 
            // regular expressions.
            return (EnableClientScript 
                        && page.Request.Browser.W3CDomVersion.Major >= 1
                        && page.Request.Browser.EcmaScriptVersion.CompareTo(new Version(1, 2)) >= 0);
        }

        protected void RegisterValidatorCommonScript() {
            
            string location = null;

            if (!Page.IsClientScriptBlockRegistered(ValidatorIncludeScriptKey)) {
            // Provide the location of the script file.
            // When using a script library, deployment can be 
            // a problem because the runtime is
            // tied to a specific version of the script file. 
            // This sample takes the easy way out and insists that
            // the file be placed in the /script subdirectory 
            // of the application.
            // In other cases, you should place it where it
            // can be shared by multiple applications and is placed 
            // in a separate directory so that different versions 
            // of a control library can run side by side.
            // The recommended pattern is to put script files in the 
            // path /aspnet_client/<assembly name>/<assembly version>/".
            location = Page.Request.ApplicationPath + "/script/";

            // Create the client script block.
             string includeScript = String.Format(IncludeScriptFormat, "javascript", location, ValidatorFileName);
            Page.RegisterClientScriptBlock(ValidatorIncludeScriptKey, includeScript);
            }

             if (!Page.IsStartupScriptRegistered(ValidatorIncludeScriptKey)) {

                 if (location == null) location = Page.Request.ApplicationPath + "/script/";

             // Provide an error message, which is localized.
            string missingScriptMessage = "Validation script is missing '" + location + ValidatorFileName + "'";

             // Create the startup script block.
            string startupScript = String.Format(ValidatorStartupScript, new object [] {missingScriptMessage, });
            Page.RegisterStartupScript(ValidatorIncludeScriptKey, startupScript);
           }

            Page.RegisterOnSubmitStatement("ValidatorOnSubmit", "return ValidatorOnSubmit();");
        }

        protected virtual void RegisterValidatorDeclaration() {
            string element = "document.getElementById(\"" + ClientID + "\")";
            Page.RegisterArrayDeclaration("Page_Validators", element);
        }

        protected override void Render(HtmlTextWriter writer) {
            bool shouldBeVisible;

            if (preRenderCalled == false) {
                // This is for design time. 
                // In this case you do not 
                // want any expandos or property checks
                // and always want the control to be visible
                // in the designer.
                propertiesChecked = true;
                propertiesValid = true;
                renderUplevel = false;
                shouldBeVisible = true;
            }
            else {
                shouldBeVisible = Enabled && !IsValid;
            }

            // Do not render if there are errors.
            if (!PropertiesValid) {
                return;
            }


            //  Specify what to display.
            ValidatorDisplay display = Display;
            bool displayContents;
            bool displayTags;
            if (RenderUplevel) {
                displayTags = true;
                displayContents = (display != ValidatorDisplay.None);
            }
            else {
                displayContents = (display != ValidatorDisplay.None && shouldBeVisible);
                displayTags = displayContents;
            }

            if (displayTags && RenderUplevel) {

                // Add this validator to the array 
                // of validators emitted in the client script. 
                RegisterValidatorDeclaration();

                // Set extra uplevel styles.
                if (display == ValidatorDisplay.None
                    || (!shouldBeVisible && display == ValidatorDisplay.Dynamic)) {
                    Style["display"] = "none";
                }
                else if (!shouldBeVisible) {
                    Debug.Assert(display == ValidatorDisplay.Static, "Unknown Display Type");
                    Style["visibility"] = "hidden";
                }
            }

            // Display the contents.
            if (displayTags) {
                RenderBeginTag(writer);
            }
            if (displayContents) {
                if (Text.Trim().Length > 0) {
                    RenderContents(writer);
                }
                else {
                    writer.Write(ErrorMessage);
                }
            }
            else if (!RenderUplevel && display == ValidatorDisplay.Static) {
                // For downlevel browsers in static mode, render a space 
                // so that table cells do not render as empty.
                writer.Write("&nbsp;");
            }
            if (displayTags) {
                RenderEndTag(writer);
            }
        }


        public void Validate() {
            if (!Visible || !Enabled) {
                IsValid = true;
                return;
            }
            // Check whether the container is invisible.
            Control parent = Parent;
            while (parent != null) {
                if (!parent.Visible) {
                    IsValid = true;
                    return;
                }
                parent = parent.Parent;
            }
            propertiesChecked = false;
            if (!PropertiesValid) {
                IsValid = true;
                return;
            }
            IsValid = EvaluateIsValid();
        }                                                  

    }
}
[Visual Basic]
' BaseDomValidator.vb.
Option Explicit
Option Strict

Imports System.ComponentModel
Imports System.Diagnostics
Imports System.Drawing
Imports System.Globalization
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.HtmlControls
Imports System.Text.RegularExpressions
Imports System.Text
Imports Microsoft.VisualBasic

Namespace DomValidators
   <DefaultProperty("ErrorMessage")> _
   MustInherit Public Class BaseDomValidator
      Inherits Label
      Implements IValidator
      
      ' Note: these script-enabled controls have two sets
      ' of client-side script. 
      ' There is a fixed set in a script library called 
      ' DomValidation.js. This goes at the top of the page
      ' and is put on the page using RegisterClientScriptBlock.
      ' The second is the dynamic block 
      ' below that contains some inline script that 
      ' should be executed at the end of the page load.
      ' This is declared using RegisterStartupScript.
Private Const ValidatorFileName As String = "DomValidation.js"
Private Const ValidatorIncludeScriptKey As String = "DomValidatorIncludeScript"
Private Const ValidatorStartupScript As String = ControlChars.CrLf & _
"<script language=""javascript"">" & ControlChars.CrLf & _
"<!--" & ControlChars.CrLf & _
"var Page_ValidationActive = false;" & ControlChars.CrLf & _
"if (typeof(Page_DomValidationVer) == ""undefined"")" & ControlChars.CrLf & _
"    alert(""{0}"");" & ControlChars.CrLf & _
"else" & ControlChars.CrLf & _
"    ValidatorOnLoad();" & ControlChars.CrLf & ControlChars.CrLf & _
"function ValidatorOnSubmit() {{" & ControlChars.CrLf & _
"    if (Page_ValidationActive) {{" & ControlChars.CrLf & _
"        return ValidatorCommonOnSubmit();" & ControlChars.CrLf & _
"    }}" & ControlChars.CrLf & _
"}}" & ControlChars.CrLf & _
"// -->" & ControlChars.CrLf & _
"</script>"

      Private Const IncludeScriptFormat As String = ControlChars.CrLf & _
"<script language=""{0}"" src=""{1}{2}""></script>"

      Private _preRenderCalled As Boolean
      Private _isValid As Boolean
      Private _propertiesChecked As Boolean
      Private _propertiesValid As Boolean
      Private _renderUplevel As Boolean


      Protected Sub New()
         _isValid = True
         _propertiesChecked = False
         _propertiesValid = True
         _renderUplevel = False
         
         ' Default forecolor for validators is Red.
         ForeColor = Color.Red
      End Sub

      <DefaultValue(GetType(Color), "Red")> _
      Public Overrides Property ForeColor() As Color
         Get
            Return MyBase.ForeColor
         End Get
         Set
            MyBase.ForeColor = value
         End Set
      End Property

      <Category("Behavior"), _
         DefaultValue(""), _
         Description("The control to validate."), _
         TypeConverter(GetType(ValidatedControlConverter))> _
      Public Property ControlToValidate() As String
         Get
            Dim o As Object = ViewState("ControlToValidate")
            If o Is Nothing Then
               Return String.Empty
            Else
               Return CStr(o)
            End If
         End Get
         Set
            ViewState("ControlToValidate") = value
         End Set
      End Property

      <Bindable(True), _
         Category("Appearance"), _
         DefaultValue(""), _
         Description("Error Message")> _
      Public Property ErrorMessage() As String Implements IValidator.ErrorMessage
         Get
            Dim o As Object = ViewState("ErrorMessage")
            If o Is Nothing Then
               Return String.Empty
            Else
               Return CStr(o)
            End If
         End Get
         Set
            ViewState("ErrorMessage") = value
         End Set
      End Property

      <Category("Behavior"), _
         DefaultValue(True), _
         Description("Enable Client Script")> _
      Public Property EnableClientScript() As Boolean
         Get
            Dim o As Object = ViewState("EnableClientScript")
            If o Is Nothing Then
               Return True
            Else
               Return CBool(o)
            End If
         End Get
         Set
            ViewState("EnableClientScript") = value
         End Set
      End Property

      Public Overrides Property Enabled() As Boolean
         Get
            Return MyBase.Enabled
         End Get
         Set
            MyBase.Enabled = value
            ' When a validator is disabled, 
            ' generally, the intent is not to
            ' make the page invalid for that round trip.
            If Not value Then
               _isValid = True
            End If
         End Set
      End Property

      <Browsable(False), _
         Category("Behavior"), _
         DefaultValue(True), _
         Description("Is Valid"), _
         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
      Public Property IsValid() As Boolean Implements IValidator.IsValid
         Get
            Return _isValid
         End Get
         Set
            _isValid = value
         End Set
      End Property

      Protected ReadOnly Property PropertiesValid() As Boolean
         Get
            If Not _propertiesChecked Then
               _propertiesValid = ControlPropertiesValid()
               _propertiesChecked = True
            End If
            Return _propertiesValid
         End Get
      End Property

      Protected ReadOnly Property RenderUplevel() As Boolean
         Get
            Return _renderUplevel
         End Get
      End Property

      <Bindable(True), _
         Category("Appearance"), _
         DefaultValue(ValidatorDisplay.Static), _
         Description("Display")> _
      Public Property Display() As ValidatorDisplay
         Get
            Dim o As Object = ViewState("Display")
            If o Is Nothing Then
               Return ValidatorDisplay.Static
            Else
               Return CType(o, ValidatorDisplay)
            End If
         End Get
         Set
            If value < ValidatorDisplay.None Or value > ValidatorDisplay.Dynamic Then
               Throw New ArgumentException()
            End If
            ViewState("Display") = value
         End Set
      End Property

      Protected Overrides Sub AddAttributesToRender(writer As HtmlTextWriter)
         ' Validators do not render the disabled attribute; 
         ' instead, they are invisible when they are disabled.
         Dim disabled As Boolean = Not Me.Enabled
         If disabled Then
            Me.Enabled = True
         End If
         MyBase.AddAttributesToRender(writer)
         
         If Me.RenderUplevel Then
            ' A validator must have an ID on the client,
            ' so if it is null, write it here.
            ' Otherwise, base.RenderAttributes takes care of it.
            If ID Is Nothing Then
               writer.AddAttribute("id", ClientID)
            End If
            
            If Me.ControlToValidate.Length > 0 Then
               writer.AddAttribute("controltovalidate", Me.GetControlRenderID(ControlToValidate))
            End If
            If ErrorMessage.Length > 0 Then
               writer.AddAttribute("errormessage", Me.ErrorMessage, True)
            End If
            Dim display As ValidatorDisplay = Me.Display
            If display <> ValidatorDisplay.Static Then
               writer.AddAttribute("display", PropertyConverter.EnumToString(GetType(ValidatorDisplay), display))
            End If
            If Not IsValid Then
               writer.AddAttribute("isvalid", "False")
            End If
            If disabled Then
               writer.AddAttribute("enabled", "False")
            End If
         End If
         If disabled Then
            Enabled = False
         End If
      End Sub

      Protected Sub CheckControlValidationProperty(name As String, propertyName As String)
         ' Get the control using the relative name.
         Dim c As Control = NamingContainer.FindControl(name)
         If c Is Nothing Then
            Throw New HttpException("Control not found.")
         End If
         
         ' Get the control's validation property.
         Dim prop As PropertyDescriptor = GetValidationProperty(c)
         If prop Is Nothing Then
            Throw New HttpException("Control cannot be validated.")
         End If
      End Sub
 
      Protected Overridable Function ControlPropertiesValid() As Boolean
         ' Determine whether the control to validate is blank.
         Dim controlToValidate As String = Me.ControlToValidate
         If controlToValidate.Length = 0 Then
            Throw New HttpException("ControlToValidate cannot be blank.")
         End If
         
         ' Check that the property points to a valid 
         ' control (if not, an exception is thrown). 
         CheckControlValidationProperty(controlToValidate, "ControlToValidate")
         
         Return True
      End Function

      Protected MustOverride Function EvaluateIsValid() As Boolean

      Protected Function GetControlRenderID(name As String) As String
         ' Get the control using the relative name.
         Dim c As Control = FindControl(name)
         If c Is Nothing Then
            Debug.Fail("We should have already checked for the presence of this")
            Return ""
         End If
         Return c.ClientID
      End Function

      Protected Function GetControlValidationValue(name As String) As String
         ' Get the control using the relative name.
         Dim c As Control = NamingContainer.FindControl(name)
         If c Is Nothing Then
            Return Nothing
         End If
         
         ' Get the control's validation property.
         Dim prop As PropertyDescriptor = GetValidationProperty(c)
         If prop Is Nothing Then
            Return Nothing
         End If
         
         ' Get the control's value as a string.
         Dim value As Object = prop.GetValue(c)
         If TypeOf value Is ListItem Then
            Return CType(value, ListItem).Value
         Else
            If Not (value Is Nothing) Then
               Return value.ToString()
            Else
               Return String.Empty
            End If
         End If
      End Function
 
      Public Shared Function GetValidationProperty(component As Object) As PropertyDescriptor
         Dim valProp As ValidationPropertyAttribute = CType(TypeDescriptor.GetAttributes(component)(GetType(ValidationPropertyAttribute)), ValidationPropertyAttribute)
         If Not (valProp Is Nothing) And Not (valProp.Name Is Nothing) Then
            Return TypeDescriptor.GetProperties(component)(valProp.Name)
         End If
         Return Nothing
      End Function

      Protected Overrides Sub OnInit(e As EventArgs)
         MyBase.OnInit(e)
         Page.Validators.Add(Me)
      End Sub

      Protected Overrides Sub OnUnload(e As EventArgs)
         If Not (Page Is Nothing) Then
            Page.Validators.Remove(Me)
         End If
         MyBase.OnUnload(e)
      End Sub

      Protected Overrides Sub OnPreRender(e As EventArgs)
         MyBase.OnPreRender(e)
         _preRenderCalled = True
         ' Force a re-query of properties for render.
         _propertiesChecked = False
         ' Work out uplevelness now.
         _renderUplevel = DetermineRenderUplevel()
         If _renderUplevel Then
            RegisterValidatorCommonScript()
         End If
      End Sub

      Protected Overridable Function DetermineRenderUplevel() As Boolean
         ' Must be on a page.
         Dim page As Page = Page
         If page Is Nothing OrElse page.Request Is Nothing Then
            Return False
         End If
         
         ' Check the browser capabilities. 
         ' This is how you can get automatic fallback to server-side 
         ' behavior. These validation controls need 
         ' the W3C DOM level 1 for control manipulation
         ' and need at least ECMAScript 1.2 for the 
         ' regular expressions.
         Return EnableClientScript AndAlso _
               page.Request.Browser.W3CDomVersion.Major >= 1 AndAlso _
               page.Request.Browser.EcmaScriptVersion.CompareTo(New Version(1, 2)) >= 0
      End Function

      Protected Sub RegisterValidatorCommonScript()
         Dim location As String = Nothing
         If Not Page.IsClientScriptBlockRegistered(ValidatorIncludeScriptKey) Then
            ' Provide the location of the script file.
            ' When using a script library, deployment can be 
            ' a problem  because the runtime is
            ' tied to a specific version of the script file. 
            ' This sample takes the easy way out and insists that
            ' the file be placed in the /script subdirectory 
            ' of the application.
            ' In other cases, you should place it where it
            ' can be shared by multiple applications and is placed 
            ' in a separate directory so that different versions 
            ' of a control library can run side by side.
            ' The recommended pattern is to put script files in the 
            ' path /aspnet_client/<assembly name>/<assembly version>/".
            location = Page.Request.ApplicationPath & "/script/"
            
            ' Create the client script block.
            Dim includeScript As String = String.Format(IncludeScriptFormat, "javascript", location, ValidatorFileName)
            Page.RegisterClientScriptBlock(ValidatorIncludeScriptKey, includeScript)
         End If
         
         If Not Page.IsStartupScriptRegistered(ValidatorIncludeScriptKey) Then
            
            If location Is Nothing Then
               location = Page.Request.ApplicationPath & "/script/"
            End If 
            ' Provide an error message, which is localized.
            Dim missingScriptMessage As String = "Validation script is missing '" & location & ValidatorFileName & "'"
            
            ' Create the startup script block.
            Dim startupScript As String = String.Format(ValidatorStartupScript, New Object() {missingScriptMessage})
            Page.RegisterStartupScript(ValidatorIncludeScriptKey, startupScript)
         End If
         
         Page.RegisterOnSubmitStatement("ValidatorOnSubmit", "return ValidatorOnSubmit();")
      End Sub

      Protected Overridable Sub RegisterValidatorDeclaration()
         Dim element As String = "document.getElementById(""" & ClientID & """)"
         Page.RegisterArrayDeclaration("Page_Validators", element)
      End Sub

      Protected Overrides Sub Render(writer As HtmlTextWriter)
         Dim shouldBeVisible As Boolean
         
         If _preRenderCalled = False Then
            ' This is for design time. 
            ' In this case you do not 
            ' want any expandos or property checks
            ' and always want the control to be visible in the designer.
            _propertiesChecked = True
            _propertiesValid = True
            _renderUplevel = False
            shouldBeVisible = True
         Else
            shouldBeVisible = Enabled And Not IsValid
         End If
         
         ' Do not render if there are errors.
         If Not PropertiesValid Then
            Return
         End If
         
         '  Specify what to display.
         Dim display As ValidatorDisplay = Me.Display
         Dim displayContents As Boolean
         Dim displayTags As Boolean
         If RenderUplevel Then
            displayTags = True
            displayContents = display <> ValidatorDisplay.None
         Else
            displayContents = display <> ValidatorDisplay.None And shouldBeVisible
            displayTags = displayContents
         End If
         
         If displayTags And RenderUplevel Then
            
            ' Add this validator to the array 
            ' of validators emitted in the client script. 
            RegisterValidatorDeclaration()
            
            ' Set extra uplevel styles.
            If display = ValidatorDisplay.None Or(Not shouldBeVisible And display = ValidatorDisplay.Dynamic) Then
               Style("display") = "none"
            Else
               If Not shouldBeVisible Then
                  Debug.Assert(display = ValidatorDisplay.Static, "Unknown Display Type")
                  Style("visibility") = "hidden"
               End If
            End If
         End If 
         ' Display the contents.
         If displayTags Then
            RenderBeginTag(writer)
         End If
         If displayContents Then
            If Text.Trim().Length > 0 Then
               RenderContents(writer)
            Else
               writer.Write(ErrorMessage)
            End If
         Else
            If Not RenderUplevel And display = ValidatorDisplay.Static Then
               ' For downlevel browsers in static mode, render a space so 
               ' that table cells do not render as empty.
               writer.Write("&nbsp;")
            End If
         End If
         If displayTags Then
            RenderEndTag(writer)
         End If
      End Sub

      Public Sub Validate() Implements IValidator.Validate
         If Not Visible Or Not Enabled Then
            IsValid = True
            Return
         End If
         ' Check whether the container is invisible.
         Dim parent As Control = Parent
         While Not (parent Is Nothing)
            If Not parent.Visible Then
               IsValid = True
               Return
            End If
            parent = parent.Parent
         End While
         _propertiesChecked = False
         If Not PropertiesValid Then
            IsValid = True
            Return
         End If
         IsValid = EvaluateIsValid()
      End Sub
   End Class
End Namespace

See Also

Validator Control Samples | Required Field Validator Control Sample | Regular Expression Validator Control Sample | Script Library for Validator Sample | Configuration File for Validator Sample | Test Page for Validator Sample | Developing a Validator Control