ASP .NET按钮事件处理程序在第一次单击时不会触发,但在PostBack后的第二次单击时才会触发。

40

背景:我正在定制一个现有的ASP .NET / C#应用程序。它有自己的小型“框架”和开发者在扩展/定制其功能时需要遵循的约定。我目前正在扩展一些管理功能,框架提供了一个合同来强制执行GetAdministrationInterface()方法的实现,该方法返回System.Web.UI.Control。这个方法在承载GUI界面的页面的Page_Load()方法中调用。

问题:我的GUI中有三个按钮,每个按钮都被分配了一个事件处理程序。我的管理GUI可以完美地加载,但点击任何一个按钮不会执行我期望的操作。然而,在第二次点击时,这些按钮起作用了。

我在每个事件处理程序方法的开头放置了断点并逐步执行了我的代码。在第一次点击时,没有触发任何事件处理程序。在第二次点击时,它们被触发了。

按钮定义示例(在GetAdministrationInterface内部)

public override Control GetAdministrationInterface()
{
    // more code...

    Button btn = new Button();
    btn.Text = "Click Me!";
    btn.Click += new EventHandler(Btn_Click);

    // more code...
}

事件处理方法定义示例

void Btn_Click(object sender, EventArgs e)
{
    // Do Something
}

Page_Load方法调用GetAdministrationInterface

protected void Page_Load(object sender, System.EventArgs e)
{
    if (!Page.IsAsync)
    {
        List<AdministrationInterface> interfaces = <DATABASE CALL>;
        foreach(AdministrationInteface ai in interfaces)
        {
            placeholderDiv.Controls.Add(ai.GetAdministrationInterface());
        }
    }
}

1
你把按钮定义和事件处理程序放在哪里了?按钮是如何添加到页面中的? - Raj Kaimal
我把Page_Load代码添加到了原始问题中。 - John
这是复制粘贴吗?因为如果是的话,你正在注册bth的点击事件而不是btn的。另外,你是否在代码中设置了断点以确保该部分实际上被调用了? - diadem
1
就记录而言,“btn.Click += Btn_Click;” 和 “btn.Click += new EventHandler(Btn_Click);” 一样有效。 - diadem
抱歉,我也注意到了代码中的错字。这不是复制粘贴。我输入了一个简化版的程序。我想我已经修正了所有错别字。感谢您关于指定事件处理程序的建议。我会尝试一下并看看它是否有所改善。 - John
显示剩余2条评论
8个回答

73

天啊!我就知道问题出在这种蠢事上。当然,完全是我的错,由于我对ASP .NET的知识缺乏。

在进行了多次谷歌搜索后,最终被谷歌怀疑是运行自动脚本的机器人而被封锁之前,我设法挤出最后一次搜索,并偶然发现了这篇文章。已经到了放弃的边缘,我尽力阅读文章,不跳过10行文字或寻找漂亮的图片。在标题为“动态创建控件分配ID”的部分,我看到了这些神奇且最令人欣喜的话:

在单击无法工作的按钮之前和之后查看源HTML,您会注意到有一个小差别。在post-back之前,按钮具有不同的HTML ID,而在之后则不同。在post-back之前,我得到的是ctl04和ctl05,在post-back之后,我得到的是ctl02和ctl03。

ASP.NET按钮通过检查Request.Form集合中其ID的值来识别事件。(实际上它是以不同方式实现的,控件本身不会检查Request.Form集合。页面通过其ID将post数据传递给控件并向那些注册为通知post数据的控件传递)。ASP.NET不会触发Click事件,因为按钮的ID在post-back之间已更改。对于ASP.NET来说,您单击的按钮与之后看到的按钮是不同的按钮。

果然,当我首次查看HTML时,我的按钮具有ID ctl04$ctl36。单击按钮后,我的按钮具有ID ctl04$ctl33

所以问题就出在这里!我只需要设置按钮的ID,就可以让我的事件处理程序被调用了!

示例解决方案:

public override Control GetAdministrationInterface()
{
    // more code...

    Button btn = new Button();
    btn.Text = "Click Me!";
    // !!THE BANE OF MY EXISTENCE!!
    btn.ID = "The_Bane_of_My_Existence";
    // !!THE BANE OF MY EXISTENCE!!
    btn.Click += new EventHandler(Btn_Click);

    // more code...
}

度过两天的好方式...


18
我有相同的问题,但这里接受的答案并不是导致问题的原因。我有一个文本框和一个搜索按钮,第一次单击按钮时没有执行搜索。按钮的事件处理程序没有被触发。但第二次单击按钮确实在服务器上触发了事件。原因如下:
如果您有一个 ,并将其 AutoPostBack 设置为 true,在键入文本框后移动到单击按钮时,文本框会立即导致回发。因此,单击按钮的事件不起作用(由于文本框的事件,页面已经回发)。这就是为什么第二次单击按钮时它能工作,因为第二次回发不涉及文本框。
将 AutoPostBack 属性设置为 false 可以解决此问题。

1
谢谢!我检查了我的代码,发现问题也是这个:我忘记在aspx页面中删除文本框标记的AutoPostBack = true属性。我使用它来调试一些服务器端验证代码,而不是使用客户端javascript。当我删除它时,哇,每次单击按钮都会触发单击事件。现在,按钮单击事件方法可以更新文本框。发布自己问题的解决方案,为我节省了数小时的在线搜索。我讨厌ASP.NET,但必须在工作中使用它。 - John Suit

6

一个快速的解决方法是为在页面加载的ASCX控件设置一个ID。例如,如果您的代码像这样:

        UserControl SpecsControl = (UserControl)Page.LoadControl("../name.ascx");
        SpecsContainer.Controls.Add(SpecsControl);

那么您需要在Controls.Add之前添加一行代码:
            SpecsControl.ID = "Aribtrary_Name";

然后您的处理程序方法在第一次点击时被触发。


1
对我来说,问题出在 UpdatePanel 上,我的按钮和文本框都在一个 UpdatePanel 中,所以当我提交时,它会导致一些奇怪的行为。将其移出 UpdatePanel ,问题得到解决。

1

我曾经遇到过同样的问题。我的按钮在第一次点击后就卡住了。对我来说,当我禁用了按钮的EnableViewState属性时,这个令人恼火的问题得到了解决。


1
我曾经遇到过同样的问题。原因是“localhost:1656/secure/login.aspx?ReturnUrl=%2f”。 如果请求包含查询字符串%2f,即使"%2f"代表"/",第一次提交也将不会成功。
可以通过在pageload中添加条件检查来避免这种情况。
protected void Page_Load(object sender, EventArgs e)
{
    string queryString = Request.QueryString.ToString();
    if(queryString == "ReturnUrl=%2f")
    {
        Response.Redirect("/secure/login.aspx");
    }
}

0

虽然没有看到完整的Page_load方法,很难确定具体情况,但似乎事件处理程序直到页面重新加载才会连接。

例如:

if (IsPostBack) {
    // Add handlers here ...
}

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接