65.9K
CodeProject 正在变化。 阅读更多。
Home

在 .NET 中进行复选框的交叉验证

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.46/5 (5投票s)

2007 年 11 月 28 日

5分钟阅读

viewsIcon

39066

downloadIcon

252

在多个复选框上同时使用客户端和服务器端验证。

Screenshot - Three checkboxes and a submit button

引言

.NET Framework 同时支持客户端和服务器端验证。客户端验证可以避免将表单发送到服务器然后因验证错误而被拒绝所花费的时间。它可以非常快速地通知用户错误。由于 .NET Framework 进行客户端验证的时机,对多个 checkbox 进行客户端交叉验证存在问题。除非程序员对 checkbox 验证给予特别关注,否则用户可能会看到似乎与他们正在做的操作正好相反的消息。

问题的解决方案

Framework 在 Change 事件发生时进行客户端验证。这发生在用户完成对控件值的任何更改并将其焦点移至其他地方之后。问题发生在“其他地方”是正在被验证的 checkbox 集合中的另一个 checkbox 时。考虑以下场景:验证规则是两个相邻的 checkbox 中至少需要有一个被选中。实现此规则的脚本会为两个 checkbox 设置。假设第二个 checkbox 最初未选中,并且用户刚刚取消选中了第一个,然后单击第二个将其选中。用户会立即看到第二个框中出现一个复选标记。由于单击第二个框会导致第一个框失去焦点,因此第一个框的验证脚本将运行。由于用户刚刚取消选中了第一个框,验证脚本会发现它未被选中。脚本的运行是为了响应第一个框的 Change 事件,该事件是由焦点切换到第二个 checkbox 触发的。在焦点改变的时刻,验证脚本发现第二个框未被选中。验证失败,用户收到错误消息。但从用户的角度来看,这是错误的,因为用户看到的是他刚刚选中了第二个框。消息说两个都没有被选中,但用户看到了第二个框中的复选标记。如果用户将焦点移到其他地方,导致第一个框失去焦点,那么验证结果对用户来说将更有意义。

因此,确保一个 checkbox 的焦点不会因为用户选中另一个框而丢失很重要。我在此提出的方法是触发 Mouseout 事件进行验证,从而在用户有机会单击另一个 checkbox 之前进行验证。Checkboxes 可能有相关的标签,单击这些标签也会切换 checkbox 的状态。此处提供的代码也处理了这些标签。

用于强制验证的技术不应将焦点转移到另一个控件,因为这会混淆 Tab 键顺序。此处介绍的技术是引发 checkbox 控件上的 Blur 事件,从而触发验证脚本运行,然后再次将焦点设置回 checkbox 本身。

Using the Code

以下是您需要添加到页面以实现此验证器的代码。此示例验证至少有一个三个 checkboxes 被选中。控件的名称出现在客户端和服务器端验证函数中。您需要修改这些函数以使用您的 checkbox 控件的名称。

将此脚本放在页面顶部 <meta> 标签之后。如果您在用户控件中进行验证,请将其放在控件页面的顶部。第一个函数是客户端验证器。第二个函数会在鼠标离开要验证的 checkbox 时改变焦点。

<script type="text/javascript" language="javascript">

    function AtLeastOneCheckbox_ClientValidate(source, args)
    {
        // Requires that In Progress, Complete, and/or Cancelled is checked

        args.IsValid = 
            document.getElementById("<%=cbxInProgress.ClientID %>").checked
          || document.getElementById("<%=cbxComplete.ClientID %>").checked
          || document.getElementById("<%=cbxCancelled.ClientID %>").checked;
    }

    /* Causes validation if mouse is moved out of control with focus 
    or its label (if there is a validator) */
    function BlurThenRefocus()
    {
        if(document.activeElement == window.event.srcElement
        || window.event.srcElement.nodeName == 'LABEL'
             && document.activeElement.id == window.event.srcElement.htmlFor)
        {
            document.activeElement.blur();
            if(window.event.srcElement.nodeName == 'LABEL')
            {
                document.getElementById
                    (window.event.srcElement.htmlFor).focus();
            }
            else
            {
                window.event.srcElement.focus();
            }
        }
    }

</script>    

在您的 checkbox 定义中,将 BlurThenRefocus() 指定为 onMouseOut 事件处理程序。在您希望显示错误消息的位置添加自定义验证器。下面是一个三个已验证 checkboxes 的示例,后跟一个用于这些框的 CustomValidatorClientValidatorFunction 引用上面定义的 AtLeastOneCheckbox_ClientValidate 函数。OnServerValidate 函数将在下面的服务器端代码中定义。

<asp:checkbox id="cbxInProgress" Runat="server" 
    Text="In Progress" tabIndex="1" onmouseout="BlurThenRefocus()">
</asp:checkbox>  
<asp:checkbox id="cbxComplete" Runat="server" Text="Complete" 
    tabIndex="2" onmouseout="BlurThenRefocus()">
</asp:checkbox>  
<asp:checkbox id="cbxCancelled" Runat="server" Text="Cancelled" 
    tabIndex="3" onmouseout="BlurThenRefocus()">
</asp:checkbox>  
<asp:CustomValidator id="AtLeastOneCheckbox" runat="server"
    ErrorMessage="Check at least one status"
    Display="Dynamic"
    OnServerValidate="AtLeastOneCheckbox_ServerValidate"
    ClientValidationFunction="AtLeastOneCheckbox_ClientValidate" /> 

接下来,我们使这个 CustomValidator 在三个 checkboxes 中任何一个的值发生更改时被执行。在页面底部或用户控件页面最底部 </form> 标签之前添加以下代码。它将 CustomValidator 与每个 checkbox 关联起来。这是通过不指定上面 CustomValidator 定义中的 ControlToValidate 来实现的,因为它将验证三个不同的控件。

<script type="text/javascript">

  ValidatorHookupControlID("<%= cbxInProgress.ClientID %>",
     document.getElementById("<%= AtLeastOneCheckbox.ClientID %>"));
  ValidatorHookupControlID("<%= cbxComplete.ClientID %>",
     document.getElementById("<%= AtLeastOneCheckbox.ClientID %>"));
  ValidatorHookupControlID("<%= cbxCancelled.ClientID %>",
     document.getElementById("<%= AtLeastOneCheckbox.ClientID %>"));

</script>

最后需要定义服务器端验证函数。它在第二个参数中返回其结果。将此代码放在定义服务器端方法的地方。

public void AtLeastOneCheckbox_ServerValidate
    (object source, ServerValidateEventArgs args)
{
    // Requires that In Progress, Complete, and/or Cancelled is checked

    args.IsValid = cbxInProgress.Checked || cbxComplete.Checked 
        || cbxCancelled.Checked;
}

运行示例项目

示例包含三个 checkboxes、一个提交按钮和一个验证摘要框。当您首次运行程序时,您会注意到将光标移到 checkboxes 上时,不会出现任何消息。这是因为验证仅在框的状态更改时执行。但是,如果您单击提交按钮,服务器端验证代码将运行,显示验证错误。但是,一旦您更改了 checkbox 的状态,您将看到的(或消除的)状态消息将是客户端验证的结果。示例的验证摘要框仅用于帮助您判断是客户端还是服务器端验证正在显示或清除消息。只有服务器端验证函数会写入摘要框。如果客户端验证失败,单击提交按钮不会导致页面回发到服务器。

您可能希望尝试使用键盘上的 Tab 键和空格键在页面上导航并更改 checkboxes 的状态。

来源

我用于将通用验证应用于多个控件的技术来自 DanielHac 的文章 CustomValidator dependent on multiple controls

历史

  • 2007/11/27:原始文章
© . All rights reserved.