Page_ClientValidate可防止后续(不相关)的LinkBut​​ton客户端单击回发

时间:2018-01-31 11:24:20

标签: asp.net webforms asp.net-4.6

TL; DR:如果单击“编辑”按钮而没有选择列表框,触发验证失败,为什么需要点击{strong>两次Delete链接>在浏览器响应之前?

使用下面的源代码获得一个非常简单的菜单,我有三个链接:

  1. New - 不执行验证并重定向到"创建"形式
  2. Edit - 检查是否已选择ListItem,如果是,则重定向到"编辑"具有作为参数提供的ID值的表单
  3. Delete - 重定向到"删除"页面,无论是否进行选择
  4. 我注意到一种奇怪的行为,并在这个简单的单页解决方案(download link from OneDrive)中重现:

    1. 加载页面
    2. 单击Edit而不从列表框中进行选择(出现验证错误)
    3. 点击Delete - 没有任何反应 - 为什么?
    4. 点击Delete - 服务器端重定向成功发生,但这应该发生在上面的第3步
    5. 以下是我的浏览器中发生的情况(在Chrome,FF和Edge中测试过) - 请注意,删除链接需要两次点击: enter image description here

      更新

      问题似乎出现在ASP.Net的表单提交代码中:

      function __doPostBack(eventTarget, eventArgument) {
          if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
      
          // On first click - this logic path is never reach, but on the second click, it is reached
      
              theForm.__EVENTTARGET.value = eventTarget;
              theForm.__EVENTARGUMENT.value = eventArgument;
              theForm.submit();
          }
      }
      

      在我手动调用if之后,我试图找出Page_ClientValidate()语句返回false的原因。

      代码

      <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication1.WebForm1" %>
      <!DOCTYPE html>
      <html xmlns="http://www.w3.org/1999/xhtml">
      <head runat="server">
          <title>Test Page</title>
          <script>
              function RedirectToPageWithSelectedId() {
                  if (Page_ClientValidate("mustSelect")) { // Asp.Net client-side validation, passing ValidationGroup as parameter
                      var li = $("#<%=ListBox1.ClientID%> option:selected");
                      var i = li.val();
                      if (parseInt(i) != NaN) {
                          window.location.href = "/edit/" + i;
                      }
                  }
              }
          </script>
      </head>
      <body>
          <form id="form1" runat="server">
              <div>
                  <p>
                      <asp:ListBox ID="ListBox1" runat="server" />
                      <asp:RequiredFieldValidator ID="Rfv1" runat="server" Text="Selection required" ValidationGroup="mustSelect" ControlToValidate="ListBox1" Display="Dynamic" />
                  </p>
                  <ul>
                      <li>
                          <asp:HyperLink ID="lnk_new" runat="server" Text="New" NavigateUrl="~/new" />
                      </li>
                      <li>
                          <asp:HyperLink ID="lnk_edit" runat="server" Text="Edit Selected" onclick="RedirectToPageWithSelectedId(); return false;" href="#" />
                      </li>
                      <li>
                          <asp:LinkButton ID="lnk_delete" runat="server" Text="Delete" />
                      </li>
                  </ul>
              </div>
          </form>
      </body>
      </html>
      

      如果需要,我可以更新以提供页面代码隐藏;只是问。

2 个答案:

答案 0 :(得分:1)

我会做这样的事情。给包含元素的<div>一个类名,并按类绑定lnk_edit的单击。现在,您可以找到是否选择了元素而无需使用ClientID。这也可以根据需要使用尽可能多的myContainer个副本,而无需添加更多jQuery代码。

<div class="myContainer">
    <p>
        <asp:ListBox ID="ListBox1" runat="server" />
    </p>
    <ul>
        <li>
            <asp:HyperLink ID="lnk_new" runat="server" Text="New" NavigateUrl="~/new" />
        </li>
        <li>
            <asp:HyperLink ID="lnk_edit" runat="server" Text="Edit Selected" href="#" CssClass="myEditLink" />
            <span class="myEditLinkWarning"></span>
        </li>
        <li>
            <asp:LinkButton ID="lnk_delete" runat="server" Text="Delete" />
        </li>
    </ul>
</div>

<script type="text/javascript">
    $('.myContainer .myEditLink').click(function () {
        $(this).closest('div').find('select option').each(function () {
            if ($(this).prop('selected')) {
                window.location.href = "/edit/" + $(this).val();
            }
        });
        $(this).closest('div').find('.myEditLinkWarning').html('Please select');
    });
</script>

答案 1 :(得分:0)

在使用Chrome的调试器进行了大量调查之后,我找到了以下逻辑和解决方法。如果我弄错了,或者是否有更好的方法与客户端的ASP.Net验证控件进行交互,请告诉我?

单击LinkBut​​ton时,ASP.Net将通过其验证逻辑工作,即使该控件未导致验证。这是让我感到惊讶的第一件事。在处理验证逻辑之前,实际上不会提交表单。

ASP.Net webforms客户端验证

在验证过程中,有两个页面级变量被设置:

<强> Page_IsValid

这是一个总体布尔值,表示所有验证器都有效。

<强> Page_BlockSubmit

这通常保持Page_IsValid的相反值,并阻止表单提交true

代码中的问题

点击我的Edit链接后,我的代码针对特定验证组启动了客户端验证:

Page_ClientValidate("mustSelect");

在该方法中,Page_IsValid变为false,因此Page_BlockSubmit变为true。这可以防止表单在显示验证错误后执行任何操作,并且是预期的。

LinkBut​​ton的点击事件引发了问题。按下时,无论LinkBut​​ton是否正在执行验证,都会执行以下JavaScript:

function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {

        // This is never reached if Page_BlockSubmit = true

        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}

最后一个验证结果仍保留在浏览器中,因此Page_BlockSubmit仍为true。这导致上述方法跳过提交表单的内部代码,这意味着表单永远不会被提交。

奇怪的是,方法完成后,Page_IsValidPage_BlockSubmit都会重置为默认值。这就是页面提交第二次编辑点击。

的原因

解决方法(或脏黑客?)

这感觉就像一个完整的黑客,但是当单击LinkBut​​ton时强制Page_BlockSubmit的值为false,一切都按预期工作,并且不需要手动开始重置validation.isvalid属性,或隐藏消息。所有其他验证组/逻辑继续正常工作,但编辑链接现在可以按用户期望的那样工作:

<asp:LinkButton ID="lnk_delete" runat="server" Text="Delete" OnClientClick="Page_BlockSubmit = false;" />

同样,我不知道是否会破坏ASP.Net的任何工作方式,并且不胜感激。