【问题标题】:Dynamic Event Handler not Firing动态事件处理程序未触发
【发布时间】:2013-10-25 19:39:53
【问题描述】:

我想根据用户在文本框中输入的数字动态创建一定数量的控件。这部分我工作得很好,但我还需要动态创建的文本框有自己的事件处理程序,这样用户就可以在其中输入一个数字,并创建更多的控件。

我的问题是我为这些控件设置的事件处理程序没有触发。也许我没有正确理解 ASP.NET 页面生命周期,但我目前正在 OnInit 事件中生成动态控件(在我在第一个文本框的 TextChanged 事件中生成它们之前,但切换到使用 OnInit事件基于我在这里找到的 Oded 的建议:Dynamically Added Event Handler Not Firing)。

编辑

我删除了我最初发布的代码,否则这篇文章会太长。

我将在此处发布我的整个 .aspx 代码和后面的代码,所以你们知道这正是我正在查看的内容。同样,由此代码生成的动态 TextBox,当其中的文本发生更改时,不会触发绑定到它的事件处理程序,它只是消失了。值得注意的是 - 我认为当您更改文本时确实会发生回发,但它不会触发事件处理程序......

ASPX 前端:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>

<!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 id="dynamicControlDiv">
            <asp:Label ID="lblEnter" runat="server" Text="Enter the amount of textboxes you want:"></asp:Label>
            <asp:TextBox ID="txtEnter" runat="server" AutoPostBack="true"></asp:TextBox>
            <asp:Label ID="lblConfirm" runat="server" Text=""></asp:Label>
        </div>
    </form>
</body>
</html>

代码隐藏:

部分类 _Default 继承 System.Web.UI.Page

Dim numOfDesiredControls As Int16

Protected Sub txtEnter_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtEnter.TextChanged

    Try
        numOfDesiredControls = Convert.ToInt16(txtEnter.Text)
        If Not numOfDesiredControls = 0 Then
            For i As Int16 = 1 To numOfDesiredControls
                Dim txtTest As New TextBox
                txtTest.Text = "dynamicTextBox"
                txtTest.ID = "dynamicTextBox" + i.ToString
                txtTest.AutoPostBack = True
                Form.Controls.Add(txtTest)
                AddHandler txtTest.TextChanged, AddressOf dynamicEventHandler
            Next
        End If
    Catch ex As Exception

    End Try
End Sub

Protected Sub dynamicEventHandler(ByVal sender As Object, ByVal e As System.EventArgs)
    ' If the event handler gets fired, reflect this by changing the text of lblConfirm
    lblConfirm.Visible = True
    lblConfirm.Text = "Event handler fired!"
End Sub

End Class

尝试使用此代码创建您自己的项目,看看您是否遇到与我相同的问题 - 动态创建的 TextBox 回发,但不会触发其事件处理程序,然后 TextBox 从页面中消失...谢谢再次求助!

【问题讨论】:

  • 这段代码应该可以正常工作。您确定循环是迭代的并且您在相应的文本框中执行任何更改(并验证它)吗?
  • 是的 - 我已经通过循环,通过,生成文本框,但是当我更改任何这些文本框中的文本时,它们的 textChanged 事件(这是我代码中的上述事件) , 不开火。动态文本框显示在页面上……只是它们的事件处理程序没有触发。
  • 请记住,在 ASP 中,行为与在 Winforms 中不同。此事件仅在更改发布到服务器(msdn.microsoft.com/en-us/library/…)时触发,例如,当用户按下回车时。
  • 您的事件添加部分很好。不工作的唯一原因是没有被调用(或者从错误的地方被调用,正如没有必要的那样,有点悲伤的尼克,顺便说一句:));或者你没有做正确的检查。
  • 我应该澄清一下 - 显然,我不希望 textChanged 事件处理程序触发,除非用户更改控件中的文本,此时它会返回服务器调用事件处理程序。

标签: asp.net vb.net event-handling page-lifecycle dynamic-controls


【解决方案1】:

由于ViewState,动态控件可能有点棘手

基本上:您正在添加动态控件以响应TextChanged 事件,该事件在InitLoad 之后以及ViewState 被反序列化之后触发。因此,您遇到了问题,因为ViewState 不知道动态控件并且与您的期望不同步。通过在Load 阶段检查txtEnter.Text 的值并在那里创建控件,您可以让您的ViewState 知道这些控件(记住,每次页面加载时都会创建这些控件!),因此您的@ 987654331@ 现在有了一个可以从中执行的上下文。

这是更正后的代码(但为简单起见,作为带有嵌入式 VB 的单个文件,您当然可以将其分离到代码隐藏文件中):

<%@ Page Language="VB" AutoEventWireup="false" %>

<script runat="server">
    Dim numOfDesiredControls As Int16

    Protected Sub Page_Load() Handles form1.Load

        Try
            numOfDesiredControls = Convert.ToInt16(txtEnter.Text)
            If Not numOfDesiredControls = 0 Then
                For i As Int16 = 1 To numOfDesiredControls
                    Dim txtTest As New TextBox
                    txtTest.Text = "dynamicTextBox"
                    txtTest.ID = "dynamicTextBox" + i.ToString
                    txtTest.AutoPostBack = True
                    ' txtTest.EnableViewState = False
                    Form.Controls.Add(txtTest)
                    AddHandler txtTest.TextChanged, AddressOf dynamicEventHandler
                Next
            End If
        Catch ex As Exception

        End Try
    End Sub

    Protected Sub dynamicEventHandler(ByVal sender As Object, ByVal e As System.EventArgs)
        ' If the event handler gets fired, reflect this by changing the text of lblConfirm
        Dim txt As TextBox
        txt = CType(sender, TextBox)
        lblConfirm.Visible = True
        lblConfirm.Text = "Event handler " + txt.Id + " fired: " + txt.Text ' append ID and text so we know which one fired it.
    End Sub
</script>

<!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 id="dynamicControlDiv">
            <asp:Label ID="lblEnter" runat="server" Text="Enter the amount of textboxes you want:"></asp:Label>
            <asp:TextBox ID="txtEnter" runat="server" AutoPostBack="true"></asp:TextBox>
            <asp:Label ID="lblConfirm" runat="server" Text=""></asp:Label>
        </div>
    </form>
</body>
</html>

这里是 Msft 关于解释行为的动态控件的起点。这方面有很多资源。

http://msdn.microsoft.com/en-us/library/hbdfdyh7.aspx

专业提示:如果可以,请不要使用动态控件。虽然这可以说是支持不使用 JavaScript 的浏览器的一种不错的方式,但目前首选的方法是使用 JavaScript 动态构建控件并使用 AJAX 进行更新。否则,您发送的数据比您需要的多。当您使用PostBack 时,每次您 POST 回服务器时,您都是 (1) 将整个 ViewState 加上表单数据上传到服务器,(2) 重建整个页面(解析 ViewState,呈现 HTML等)在服务器上,以及 (3) 将所有 HTML(和ViewState)发送回客户端。这对于适用电源使用和数据计划费率的移动设备来说尤其麻烦。

【讨论】:

  • 感谢您的建议。这就是我在开始使用 OnInit 之前所做的,但它仍然不起作用。奇怪的是我尝试用动态按钮替换动态文本框,当我点击动态添加的按钮时,我为其添加的事件处理程序不会触发,但按钮消失了......我很困惑。
  • 你能发布完整的代码吗?还 - 认为使用 Repeater 控件和使用 ItemCommand 处理程序执行此操作可能会更好
  • 之前没用过Repeater控件,不过今天早上我要学习一下。我遇到的问题,最初是在这个帖子中发布的,但仍然困扰着我:\。
  • 抱歉,除非您发布完整的 .aspx 和代码隐藏代码,否则无法为您提供更多帮助......关于您到底在做什么有太多未知数。
  • 明白了。如果您仍然愿意提供帮助,我将发布我的整个 .aspx 页面和代码。我当然会很感激!我正在编辑原始帖子。
【解决方案2】:

您需要将动态文本框的 AutoPostback 属性设置为 True,以便它们触发 TextChanged 事件。

Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
    MyBase.OnInit(e)

    For i As Int16 = 0 To 5
        Dim txtTest As New TextBox
        txtTest.Text = "this is an OnInit generated textbox"
        txtTest.ID = "testOnInit" + i.ToString
        txtTest.AutoPostBack = True  
        Form.Controls.Add(txtTest)
        AddHandler txtTest.TextChanged, AddressOf txtTest_TextChanged
    Next
End Sub

Protected Sub txtTest_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs)
    Dim txt As TextBox = DirectCast(sender, TextBox)
    lblTest.Text = txt.ID & " value changed to " & txt.Text
End Sub

【讨论】:

  • 非常感谢您指出这一点!将 AutoPostBack 属性设置为 True 确实允许 txtTest 响应更改的文本。我不知道我是怎么忘记这件事的!但是,就像我使用按钮而不是文本框一样,当我更改文本时,动态生成的控件(无论是按钮还是文本框)都会消失。它不会触发分配给它的事件处理程序(我设置了一个断点来确认 - 事件处理程序没有执行)。
  • 我想知道 - 未动态生成的控件的事件处理程序在其方法定义的末尾有“句柄 ”。我在动态控件/事件处理程序上看到的所有示例都显示将这部分排除在外。显然,如果控件尚不存在,事件不知道它正在处理什么控件,因此如果您尝试定义它,.NET 将看到这一点并且不允许程序运行。我应该以不同的方式声明事件处理程序方法本身吗?
猜你喜欢
  • 2011-04-25
  • 2012-04-15
  • 2011-09-07
  • 1970-01-01
  • 2014-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多