TextBox AutoPostBack抢占了更多事件

时间:2011-07-08 18:55:12

标签: c# asp.net

在一个简单的ASP页面中,TextBox AutoPostBack事件将阻止按钮点击事件(除非快速点击按钮)和其他控件的AutoPostBack事件(如ListBox)。

这里有类似的问题,但我对被迫使用客户端或AJAX解决方案感到不满:Have to click button twice in asp.net (after autopostback textbox)

示例ASPX页面:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="temp.aspx.cs" Inherits="temp" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:TextBox ID="TextBox1" runat="server" AutoPostBack="True" OnTextChanged="PostBack"></asp:TextBox>
            <asp:Button ID="Button1" runat="server" OnClick="PostBack" Text="Button" /><br />
            <asp:ListBox ID="ListBox1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="PostBack">
                <asp:ListItem>value1</asp:ListItem>
                <asp:ListItem>value2</asp:ListItem>
            </asp:ListBox><br />
            <br />
            Events Fired:<br />
            <asp:TextBox ID="TextBox2" runat="server" Height="159px" TextMode="MultiLine" Width="338px"></asp:TextBox></div>
        </form>
    </body>
    </html>

C#代码背后:

public partial class temp : System.Web.UI.Page
{
    protected void PostBack(object sender, System.EventArgs e)
    {
        this.TextBox2.Text += string.Format("PostBack for - {0}\n", ((System.Web.UI.Control)sender).ID);
    }
}

我已经能够通过使用mousedown而不是单击事件提交表单来部分解决按钮的问题(我还在客户端阻止了额外的AutoPostBack事件,并在按钮点击事件服务器端处理了任何额外的字段更改)< / p>

然而,这意味着我的按钮在标准(点击发布)方式上表现不佳。

这个问题有没有更好的解决方案,不需要尝试在javascript客户端执行所有操作? (我正在编写大量代码,在这些回发期间读取服务器数据,因此javascript不是理想的解决方案。)

我也试图避免切换到这些页面的AJAX库,因为我添加的每个新库都必须经过安全审核等。

注意:我目前正在使用ASP.Net 2.0 / VS 2005,但是如果在以后的版本中修复了这种类型的问题,这将是一个令人信服的升级论据。 (据我所知,ASP.Net 4 / VS 2010中似乎也出现了同样的问题)

2 个答案:

答案 0 :(得分:6)

在字段(或其他输入控件)上设置AutoPostBack =“true”的原因是因为您希望页面在控件的数据发生更改时进行回发 - 而无需用户单击按钮。听起来这正是发生的事情:当场失去焦点时,页面会进行回发。

也许我误解了这个问题?您能否提供一些有关您需要页面/表单行为的更多信息?

编辑:根据OP的评论提供更多信息。

我想我理解:“正常”情况是他们从DropDownList1中选择一些东西,然后根据DropDownList1中的选定项自动回放设置DropDownList2的值。但是,用户可能不关心第二个列表;如果他们单击“搜索”,您希望按钮单击基本上中止autopostback(已在进行中),并启动新的回发。

不幸的是,我不认为任何版本的ASP.NET中都有任何功能可以“中止”正在进行的回发(无论如何不是来自客户端代码)。因此,为了实现上述行为,您将不得不在标准ASP.NET回发行为之外执行某些操作。这里有一些想法,但绝不是一个详尽的清单:

  • 使用AJAX和JS检索DropDownList2的内容。如果用户在该ajax调用正在进行时单击搜索,则该页面应立即回发。
  • 在页面中以JSON格式存储所有可能的DropDownList2数据;当List1更改时,使用纯客户端JS填充List2。同样,如果用户点击“搜索”,该页面将立即回发。根据可能的List2条目池的大小,这可能会使页面大小过大而无法使用。
  • 当List1更改选择时,使用客户端JS禁用搜索按钮。在autopostback(填充List2)完成之前,用户将无法单击“搜索”。

希望这有帮助!

答案 1 :(得分:3)

为了使客户端更具交互性并减少发送所有视图状态并重新绘制页面,我在混合中添加了一点jquery。它使得你提出的建议成为可能。 jquery甚至附带了asp.net MVC框架,因此在使用asp.net时没有任何耻辱。

这是一个使用jquery的简单示例,它演示了我想要的内容。

首先,在aspx文件中,添加对jquery库的引用。我用 谷歌内容交付网络,所以你甚至没有将此文件添加到您的VS项目。 然后从除按钮之外的所有服务器控件中取出自动回发引用。我离开那一个继续做回发因为我怀疑在某些时候你想要一个常规的回复,所有其他控件都使用ajax来获得服务器端响应。

我首先使用您的示例页面进行了这些修改:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="temp.aspx.cs" Inherits="temp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
    $(document).ready(function () {
        // Establish where the output goes.
        var outputObject = $("#<%=TextBox2.ClientID %>");

        // create a function to do an ajax postback
        function doAjaxPostback(sender, value) {
            $.ajax({
                type: "POST",
                url: "temp2.aspx",
                data: "id=" + sender.attr("id") + "&value=" + value,
                success: function (data) { outputObject.append("<br />" + data) }
            });
        }

        // Use jquery to wire up the event handler. We use the ClientID property in case these 
        // elements get embeded in some other server control container later.
        $("#<%=TextBox1.ClientID %>").keyup(function (event) { doAjaxPostback($(this), $(this).val()); });
        $("#<%=TextBox1.ClientID %>").change(function (event) { doAjaxPostback($(this), $(this).val()); });
        $("#<%=ListBox1.ClientID %>").change(function (event) { doAjaxPostback($(this), $(this).val()); });

        // Use a plain html button tag for ajax only. The server control button gets rendered as
        // a submit button which requires it to be handled a little differently.
        $("#PlainButton").click(function (event) { doAjaxPostback($(this), $(this).attr("value")); event.preventDefault(); });
    });
</script>
    <form id="form1" runat="server">
    <div>
        <asp:TextBox ID="TextBox1" runat="server" ></asp:TextBox>
        <asp:Button ID="Button1" runat="server" OnClick="PostBack" Text="Button" /><br />
        <button id="PlainButton" value="Plain Old Button">Ajax Only, No postback</button>
        <br />
        <asp:ListBox ID="ListBox1" runat="server" >
            <asp:ListItem>value1</asp:ListItem>
            <asp:ListItem>value2</asp:ListItem>
        </asp:ListBox>
        <br />
        <br />
        Events Fired:<br />
        <asp:TextBox ID="TextBox2" runat="server" Height="159px" TextMode="MultiLine" Width="438px"></asp:TextBox>

        </div>
    </form>
</body>
</html>

然后对于后面的代码,我做了一个小小的改动,所以我们可以报告我们得到一个常规的回发与ajax类型:

        protected void PostBack(object sender, System.EventArgs e)
        {
            this.TextBox2.Text += "\n\nGot an asp.net postback\n\n"
                + string.Format("PostBack for - {0}\n", ((System.Web.UI.Control)sender).ID);
        }

好吧,所以我试图不要过于花哨但我想证明这是多么容易,所以我做了第二页,temp2.​​aspx但是只留下了aspx文件,因为我只需要后面代码中的内容:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class temp2 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            string id = string.Empty;
            string value = string.Empty;
            Response.Clear();

            if (Request.Form == null || Request.Form.Count < 1)
            {
                Response.Write("I got nothin'");
                Response.Flush();
                Response.End();
                return;
            }

            id = Request.Form["id"];
            value = Request.Form["value"];

            Response.Write(string.Format("\nevent from: {0}; value={1}",id,value));
            Response.Flush();
            Response.End();
        }
    }
}

请注意,我所做的是清除,写入,刷新并结束响应,因此只有我们想要的文本被发送回调用者。我们本可以在原始临时页面的page_load中做一些奇特的东西来检查它是否是来自ajax函数的调用,如果传入的Request.Form不包含某个字段等,它将不会清除或刷新响应。通过将其作为单独的页面,我希望简化代码。这也开辟了可能性。

假设您有一个国家/地区下拉,其中包含加拿大和美国,并且当它发生变化时,您希望发回数据以使用适当的值填充州/省下拉列表。通过将查找代码放在自己的页面上,就像我使用temp2.​​aspx一样,您可以从应用程序中需要此类服务的所有页面调用它。

祝你好运,如果您在理解我的代码时遇到任何问题,请告诉我。