Частичная проверка правильности ввода данных.

Довольно часто можно столкнуться с проблемой, когда на одной странице находятся две «формы», правильность данных в которых необходимо проверять по отдельности.
Обычно приходиться жертвовать клиентской частью проверок и делать все проверки на сервере, но не очень удобно.

Далее мы рассмотрим способы, которыми можно реализовать частичную проверку. Первый способ достаточно прост и подходит, когда у нас все проверяющие элементы управления (Валидаторы) находятся на одной странице. Ниже представлен пример того, как это реализуется.

<%@ Page %>
<%@
Import Namespace="System.Collections"%>
<
head>
  <
script language="javascript">
    function
EnableValidationGroup( activeValidators ) {
      
// Если на странице нет валидаторов то ничего не делаем
      
if (typeof(Page_Validators)=='undefined') return;
 
      
//Выключаем все валидаторы
      
for( i = 0; i < Page_Validators.length; i++ )
       
Page_Validators[i].enabled = false;
 
      
//Включаем нужные нам валидаторы
      
for( i = 0; i < activeValidators.length; i++ )
       
activeValidators[i].enabled = true;
    }
 
</script>
  <script runat="server" language="c#">
    Hashtable _validationGroups = new Hashtable();
 
    void CreateValidationGroup(string name, params BaseValidator[] validators) {
      _validationGroups[name] = validators;
      foreach(BaseValidator validator in validators) {
        RegisterArrayDeclaration(name,string.Format("document.all["{0}"]",validator.ClientID)); 
      }
    }
   
    bool IsValidationGroupValid(string name) {
      BaseValidator[] validators = (BaseValidator[])_validationGroups[name];
      bool isValid = true;
      foreach(BaseValidator validator in validators) {
        isValid &= validator.IsValid;
      }
      return isValid;
    }
 
    void RegisterControlValidationGroup(Button button,string name) {
      button.Attributes.Add("onclick","EnableValidationGroup(" + name + ");");
    }
    void Page_Load(object sender, EventArgs e) {
      CreateValidationGroup("__validatorGroup1",_passwordRequired,_loginRequired);
      CreateValidationGroup("__validatorGroup2",_titleRequired,_messageRequired);
      
      RegisterControlValidationGroup(_loginButton,"__validatorGroup1");
      RegisterControlValidationGroup(_postButton,"__validatorGroup2");
    }
   
    void OnLoginButtonClick(object sender, EventArgs e) {
      if (!IsValidationGroupValid("__validatorGroup1")) {
        return;
      }
      Response.Write("Login sucessfull");
    }
    void OnPostButtonClick(object sender, EventArgs e) {
      if (!IsValidationGroupValid("__validatorGroup2")) {
        return;
      }
      Response.Write("Post sucessfull");
    }   
  </script>
</head>
<body>
  <form runat="server">
  <table width="100%">
    <tr>
      <td width="200px" valign="top">
        <fieldset>
          <legend>Login</legend>
          <table width="200">
            <tr>
              <td>Login:</td>
              <td>
                <asp:TextBox id="_loginText" runat="server" Width="150px"/>
                <asp:RequiredFieldValidator  ErrorMessage="Login is required field"
                  runat="server" id="_loginRequired" Text="*" Display="None"
                  ControlToValidate="_loginText"/>
              </td>
            </tr>
            <tr>
              <td>Password:</td>
              <td><asp:TextBox id="_passwordText" TextMode="Password"
                runat="server" Width="150px"/>
              <asp:RequiredFieldValidator ErrorMessage="Password is required field"
                runat="server" id="_passwordRequired" Text="*"
                Display="None" ControlToValidate="_passwordText"/>
              </td>
            </tr>
            <tr>
              <td></td>
              <td><asp:Button runat="server" id="_loginButton"
                Text="Log In" Width="100px" OnClick="OnLoginButtonClick"/></td>
            </tr>
          </table>
        </fieldset>
      </td>
      <td width="100%">
        <fieldset>
          <legend>Message Post</legend>
          <table>
            <tr>
              <td>Title:</td>
              <td><asp:TextBox id="_titleText" runat="server" Width="400px"/>
              <asp:RequiredFieldValidator ErrorMessage="Title is required field"
                runat="server" id="_titleRequired" Text="*" Display="None"
                ControlToValidate="_titleText"/>
              </td>
            </tr>
            <tr>
              <td colspan="2">Message:</td>
            </tr>
            <tr>
              <td colspan="2">
                <asp:TextBox  TextMode="MultiLine" Rows="20" id="_messageText"
                  runat="server" Width="600px"/>
                <asp:RequiredFieldValidator runat="server"
                  ErrorMessage="Message is required field" id="_messageRequired" Text="*"
                  Display="None" ControlToValidate="_messageText"/>
              </td>
            </tr>
            <tr>
              <td align="right" colspan="2"><asp:Button id="_postButton"
                runat="server" Text="Post" Width="100px"
                OnClick="OnPostButtonClick"/></td>
            </tr>
          </table>
        </fieldset> 
      </td>
    </tr>
  </table>
    <asp:ValidationSummary runat="server" ShowMessageBox="true" ShowSummary="false"/>
  </form>
</body>

Но, в случае использования данного функционала на нескольких страницах, приходится делать Copy & Paste кода, что не очень красиво и муторно, тем более, что достаточно просто допустить ошибку. Для того чтобы избежать этого, мы инкапсулируем всю логику в отдельный элемент управления.

using System;
using System.IO;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
namespace TestWebControls
{
  [
   
Designer("System.Web.UI.Design.WebControls.PanelDesigner, System.Design,
    Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
),
   
PersistChildren(true), ParseChildren(false)]
  public class
ValidationGroup : Panel
 
{
    public static
readonly string ValidationGroupScriptKey = "__validationGroupScript";
    protected
override void Render(HtmlTextWriter writer)
    {
      
base.RenderChildren(writer);
    }
    protected
override void OnPreRender(EventArgs e)
    {
      if(!
Page.IsClientScriptBlockRegistered(ValidationGroupScriptKey))
      {
       
string resourceName = typeof(ValidationGroup).Namespace +
         
".Resources.ValidationGroup.js";
       
using(StreamReader reader = new StreamReader(
         
typeof(ValidationGroup).Assembly.GetManifestResourceStream(resourceName)))
        {
         
Page.RegisterClientScriptBlock(ValidationGroupScriptKey,reader.ReadToEnd());
        }
      }
      
RegisterValidators(this);
      
base.OnPreRender (e);
    }
    public
string GetValidationGroupScript()
    {
      return
string.Format("if (typeof({0}_Validators)!='undefined') " +
         
"{{ EnableValidationGroup({0}_Validators,{0}_InitialEnabled)}} else " +
         
"{{EnableValidationGroup();}};",ClientID);
    }
    public
void RegisterControl(Button button)
    {
      
button.Attributes.Add("onclick",GetValidationGroupScript());
    }
    public
void RegisterControl(LinkButton button)
    {
      
button.Attributes.Add("onclick",GetValidationGroupScript());
    }
    public
bool IsValid
   
{
      
get
      
{
        return
CheckValidators(this);
      }
    }
   
bool CheckValidators(Control c)
    {
      
bool isValid = true;
      foreach(
Control childControl in c.Controls)
      {
        if (
childControl is BaseValidator && childControl.Visible)
        {
         
BaseValidator validator = (BaseValidator)childControl;
          if (
validator.Enabled)
          {
            
isValid &= validator.IsValid;
          }
        }
        else
        {
          if (
childControl is INamingContainer && childControl.Visible)
          {
            
isValid &= CheckValidators(childControl);
          }
        }
      }
      return
isValid ;
    }
   
void RegisterValidators(Control c)
    {
      foreach(
Control childControl in c.Controls)
      {
        if (
childControl is BaseValidator && childControl.Visible)
        {
         
Page.RegisterArrayDeclaration(ClientID + "_Validators",
            
string.Format("document.all['{0}']",childControl.ClientID));
         
Page.RegisterArrayDeclaration(ClientID + "_InitialEnabled",
            ((
BaseValidator)childControl).Enabled.ToString().ToLower());
        }
        else
        {
          if (
childControl is INamingContainer && childControl.Visible)
          {
            
RegisterValidators(childControl);
          }
        }
      }
    }
  }
}

Кроме того, как видно из кода, клиентский скрипт был вынесен в ресурсный файл

<script language="javascript">
  function
EnableValidationGroup( activeValidators, initialValues ) {
   
// Если на странице нет валидаторов то ничего не делаем
   
if (typeof(Page_Validators)=='undefined') return;
   
//Выключаем все валидаторы
   
for( i = 0; i < Page_Validators.length; i++ )
      
Page_Validators[i].enabled = false;
    if (
typeof(activeValidators)=='undefined') return;
   
//Включаем нужные нам валидаторы
   
for( i = 0; i < activeValidators.length; i++ )
      
activeValidators[i].enabled = initialValues[i];
  }
</script>

Ну и в конце, приведу пример использования нашего элемента управления в aspx страничке.

<%@ Page %>
<%@
Register tagPrefix="ej" Namespace="TestWebControls" Assembly="TestWebControls"%>
<%@
Import Namespace="System.Collections"%>
<
head>
  <
script runat="server" language="c#">
   
void Page_Load(object sender, EventArgs e) {
      
_group1.RegisterControl(_loginButton);
      
_group2.RegisterControl(_postButton);
    }
   
   
void OnLoginButtonClick(object sender, EventArgs e) {
      if (!
_group1.IsValid) {
        return;
      }
      
Response.Write("Login sucessfull");
    }
   
void OnPostButtonClick(object sender, EventArgs e) {
      if (!
_group2.IsValid) {
        return;
      }
      
Response.Write("Post sucessfull");
    }   
 
</script>
</head>
<body>
  <form runat="server">
    <table width="100%">
      <tr>
        <td width="200px" valign="top">
          <fieldset>
            <legend>Login</legend>
            <ej:ValidationGroup runat="server" id="_group1">
              <table width="200">
                <tr>
                  <td>Login:</td>
                  <td>
                    <asp:TextBox id="_loginText" runat="server" Width="150px" />
                    <asp:RequiredFieldValidator ErrorMessage="Login is required field"
                      runat="server" id="_loginRequired" Text="*"
                      Display="None" ControlToValidate="_loginText" />
                  </td>
                </tr>
                <tr>
                  <td>Password:</td>
                  <td><asp:TextBox id="_passwordText" TextMode="Password"
                    runat="server" Width="150px" />
                    <asp:RequiredFieldValidator ErrorMessage="Password is required field"
                      runat="server" id="_passwordRequired"
                      Text="*" Display="None" ControlToValidate="_passwordText" />
                  </td>
                </tr>
                <tr>
                  <td></td>
                  <td><asp:Button runat="server" id="_loginButton" Text="Log In"
                    Width="100px" OnClick="OnLoginButtonClick" /></td>
                </tr>
              </table>
            </ej:ValidationGroup>
          </fieldset>
        </td>
        <td width="100%">
          <fieldset>
            <legend>Message Post</legend>
            <ej:ValidationGroup runat="server" id="_group2">
              <table>
                <tr>
                  <td>Title:</td>
                  <td><asp:TextBox id="_titleText" runat="server" Width="400px" />
                    <asp:RequiredFieldValidator ErrorMessage="Title is required field"
                      runat="server" id="_titleRequired" Text="*"
                      Display="None" ControlToValidate="_titleText" />
                  </td>
                </tr>
                <tr>
                  <td colspan="2">Message:</td>
                </tr>
                <tr>
                  <td colspan="2">
                    <asp:TextBox TextMode="MultiLine" Rows="20" id="_messageText"
                      runat="server" Width="600px" />
                    <asp:RequiredFieldValidator runat="server"
                      ErrorMessage="Message is required field" id="_messageRequired" Text="*"
                      Display="None" ControlToValidate="_messageText" />
                  </td>
                </tr>
                <tr>
                  <td align="right" colspan="2"><asp:Button id="_postButton"
                    runat="server" Text="Post" Width="100px"
                    OnClick="OnPostButtonClick" /></td>
                </tr>
              </table>
            </ej:ValidationGroup>
          </fieldset>
        </td>
      </tr>
    </table>
    <asp:ValidationSummary runat="server" ShowMessageBox="true" ShowSummary="false" />
  </form>
</body>

Вот и все.

Автор: Eugene Jenihov