【问题标题】:ASP.NET dynamic Command Button event not firingASP.NET 动态命令按钮事件未触发
【发布时间】:2010-12-19 01:08:47
【问题描述】:

我正在尝试动态创建命令按钮,但单击相关按钮似乎不会引发相应的 CommandButton_Click 事件。我注意到在 SO 的示例中,为 Button.OnCommand 以及 CommandName 和 CommandArgument 设置了一个属性,但它不是智能感知中的选项。

所以问题是,我在这里做错了什么(下面没有 OnCommand 的代码),是否以其他方式访问它 - 如果是这样,为什么我找到的示例都显示为 .OnCommand?

编辑: 为了进一步提供帮助,我添加了处理程序,但事件仍未触发。这些按钮位于 UpdatePanel 中,并在每次回发时重建(连同处理程序)。我已经创建了一个我正在做的简化示例,如下所示如果按钮事件触发,它会将“事件触发”写入 txtTestFired 文本框 - 可以说我从未见过。这真的让我发疯了,非常感谢任何帮助。

.aspx 文件

<form id="frmMain" runat="server">
    <asp:ScriptManager ID="scmAddProducts" runat="server">
    </asp:ScriptManager>
    <asp:updatepanel runat="server">
        <ContentTemplate>
            <asp:TextBox ID="txtProduct" runat="server"></asp:TextBox>
            <br />
            <asp:Button ID="btnAddItem" runat="server" Text="Add Line" />&nbsp;
            <asp:TextBox ID="txtTestFired" runat="server"></asp:TextBox>
            <br />
            <br />
            <asp:Panel ID="pnlAddedLines" runat="server"></asp:Panel>
        </ContentTemplate>
    </asp:updatepanel>
</form>

.aspx.vb 文件

Protected Sub btnAddItem_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAddItem.Click
    Dim dtItems As New System.Data.DataTable

    If Session("Items") Is Nothing Then
        Dim dcColumn As New System.Data.DataColumn
        dcColumn.DataType = Type.GetType("System.String")
        dcColumn.ColumnName = "Product"
        dtItems.Columns.Add(dcColumn)
        Session("Items") = dtItems
    End If

    dtItems = CType(Session("Items"), System.Data.DataTable)
    Dim drRow As System.Data.DataRow
    drRow = dtItems.NewRow()
    drRow("Product") = txtProduct.Text
    dtItems.Rows.Add(drRow)

    Session("Items") = dtItems
    txtProduct.Text = ""
End Sub
Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
    If Not Session("Items") Is Nothing Then
        Dim dtItems As System.Data.DataTable = CType(Session("Items"), System.Data.DataTable)
        Dim iItemIndex As Integer = 1
        For Each drRow In dtItems.Rows
            Dim btnClose As New Button
            btnClose.ID = "btnClose" & iItemIndex
            btnClose.CssClass = "formCloseButton"
            btnClose.Text = "X"
            AddHandler btnClose.Click, AddressOf Button_Clicked
            pnlAddedLines.Controls.Add(btnClose)
            btnClose = Nothing

            Dim txtProduct = New TextBox
            txtProduct.ID = "txtProduct" & iItemIndex
            txtProduct.CssClass = "formText"
            txtProduct.Text = drRow("Product")
            txtProduct.Columns = "40"
            pnlAddedLines.Controls.Add(txtProduct)
            iItemIndex += 1

            Dim litHR = New Literal
            litHR.Text = "<hr />"
            pnlAddedLines.Controls.Add(litHR)
            litHR = Nothing
        Next
    End If
End Sub
Private Sub Button_Clicked(ByVal sender As Object, ByVal e As System.EventArgs)
    txtTestFired.Text = "EVENT FIRED"
End Sub

【问题讨论】:

  • 在我的回答中查看编辑以回复您的编辑
  • 移动到 page_load 并且事件触发......但是......现在是一个不同的问题(这就是我最初将它放在 pre_render 中的原因)。按钮单击事件(添加文本框等)发生在页面生命周期中的页面加载之后。因此,当我将它添加到我的测试中时,我遇到了系统总是一个回发的问题 - 即您必须在第一组控件呈现之前提交两次。
  • 我认为您的原始问题已正确解决(事件未触发)-您当前的问题可能应该作为单独的问题添加。听起来有点像您添加新控件为时已晚,您是否在点击处理程序期间重定向?
  • 谢谢,事件仍然没有在需要的上下文中触发。如果这是不可能的,那么sobeit,但我宁愿在创建一个几乎重复的问题之前在上下文中继续这个问题。问题的症结在于用户单击了一个创建控件的按钮。控件不知道它们需要在 page_load 中创建,因为尚未处理按钮单击事件。有一个快速而肮脏的修复方法,每次提交后都会进行虚假的回发或重新加载,但这既笨拙又令人讨厌。

标签: asp.net vb.net webforms button


【解决方案1】:

你必须像这样连接它(在 C# 中):

myButton.Click += new EventHandler(this.Button_Clicked);

或者你可以注入属性 --> onclick = "Button_Clicked" 像这样:

myButton.Attributes.Add("onclick", "Button_Clicked");

如果你想在 VB.NET 中使用它,请转到 to this page 并把自己搞砸 - 我可以为你做,但有什么意义 :)

编辑:请记住,每次页面加载都必须重新连接事件处理程序(如上所示)。

编辑:好的 - 现在我看到了您添加了其余代码的问题。您正在连接 pre_render 上的事件处理程序。事件处理程序在 load_complete 之前执行,这发生在 pre_render 之前。这就是你的 event_handler 不执行的原因:你在页面生命周期中添加它太晚了。将该代码放入 page_load 例程中,它应该可以工作。

【讨论】:

  • 这是 C#,而不是你在 VB.NET 中的做法
  • 如果你不能花 13 秒时间自己找出细微的语法差异,上帝会帮助你的客户。
  • 我看到你在回答中花时间这样做......谈论实践你所宣扬的:)
  • @Johnldol 实际上,我指的是 Chalkey 关于答案不在 VB 中的评论。我的观点是“如果你不能把这个小东西从 C# 移植到 VB,那么你必须解决的问题比让你的事件触发更大。”这更像是一个半开玩笑的评论。我认为您个人超越了发布转换器。我实际上是目前唯一为您的帖子投票的人...
【解决方案2】:

本质上,您需要在页面加载时创建一次原始控件,以便能够处理按钮单击,然后您需要清除控件并在按钮单击处理程序中重新生成它们,或者像您所做的那样预渲染 - 我认为它在点击处理程序上更干净,因此您需要在两者中使用相同的代码(最好重构为单独的方法)

下面的示例意味着对您的代码更改最少:

Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
    If Not Session("Items") Is Nothing Then
        pnlAddedLines.Controls.Clear()
        GenerateControls()
    End If
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    If Not Session("Items") Is Nothing Then
        GenerateControls()
    End If
End Sub
Private Sub GenerateControls()
    Dim dtItems As System.Data.DataTable = CType(Session("Items"), System.Data.DataTable)
    Dim iItemIndex As Integer = 1
    For Each drRow In dtItems.Rows
        Dim btnClose As New Button
        btnClose.ID = "btnClose" & iItemIndex

【讨论】:

  • 谢谢 - 我会试一试
  • 谢谢-根据我的实际需求,您的方法略有不同-我拥有的是一个计数器,它创建 n+1 个命令按钮,然后清除它们以进行按钮单击可能导致的添加/删除(要么添加另一个,要么删除一个) - 这样我永远不会有超过+2的处理程序过剩,这是一个令人担忧的问题。像梦想一样工作 - 谢谢。
  • 不错的时机 :) - 我可能会在 ViewState 中存储一个计数器,而不是在会话中存储一个 DataTable?
  • 我在 ViewState 中发现的问题是,如果用户刷新页面,控件会丢失(每行大约有 6 个控件) - 表单可能需要一段时间才能构建,所以它会如果输入的数据在刷新时没有持续存在,那对他们来说有点令人发指。再次感谢您一路上的所有帮助(顺便说一句,您的回答 +1 代表,抱歉我不能提供更多)
【解决方案3】:

我遇到了同样的问题,我加载控件很好。事件是第一次触发,但不是第二次。问题是我没有绑定到控件的唯一标识符。因此,我向要添加到页面的控件添加了一个唯一的 ID 字段,并且每次单击都可以正常工作。

【讨论】:

  • 能否请您用一些代码详细说明这个答案?
【解决方案4】:

您需要连接点击事件。看这段代码...

Partial Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Dim button1 As New Button
        Dim button2 As New Button

        button1.ID = "button1"
        button1.Text = "Button 1"
        button2.ID = "button2"
        button2.Text = "Button 2"

        AddHandler button1.Click, AddressOf OnClick
        AddHandler button2.Click, AddressOf OnClick

        form1.Controls.Add(button1)
        form1.Controls.Add(button2)

    End Sub

    Private Sub OnClick(ByVal sender As Object, ByVal e As System.EventArgs)

        Dim buttonId As String

        buttonId = DirectCast(sender, Button).ID

        Response.Write("Button clicked: " + buttonId)

    End Sub

End Class

希望这会有所帮助...

【讨论】:

  • 谢谢 - 我已经把它放进去,它仍然不会触发!我现在想知道这是否是因为按钮是在 UpdatePanel 中创建的 - 在您的知识中可能是这种情况吗?
【解决方案5】:

正确的做法是:

  1. OnLoad - 生成动态内容(创建动态按钮)
  2. 按钮 OnClick - 使用事件并重新生成正确的内容

但它需要生成两次内容 - 一次用于创建按钮以处理事件,然后擦除旧内容并生成正确的一秒钟。您可以像这样解决它:

  1. OnLoad - 检查按钮是否被点击
  2. PreRender - 使用动态按钮生成正确的内容(内容只生成一次)

我的例子:

<script type="text/javascript" language="javascript">
    function SetPostBackAction(Action,ReturnValue)
    {
        if(ReturnValue)
            document.getElementById('<%=hfPostBackAction.ClientID%>').value=Action;
        return ReturnValue;
    }
</script>
<asp:HiddenField ID="hfPostBackAction" EnableViewState="false" runat="server" />

在代码中:

protected void Page_PreRender(object sender, EventArgs e)
{
    //Dynamic button in PreRender
    System.Web.UI.WebControls.Button btn=new System.Web.UI.WebControls.Button()
    btn.ID=string.Format("DeleteButton_SomeData{0}", 12345);
    btn.Text="Delete";
    btn.OnClientClick=string.Format("return SetPostBackAction('DeleteButton_SomeData{0}',window.confirm('Are you sure to delete?'))", 12345);
    btn.Click+=new EventHandler(btnDelete_Click);//This method will not be called if button is created in PreRender
}

protected void Page_Load(object sender, EventArgs e)
{
    //Do something...
    //Check Action
    ProccessAction();//You can check action whereever you want
}

protected void ProccessAction()
{
    string Action=Request.Form[hfPostBackAction.UniqueID]??string.Empty;
    int SomeData;

    if(Action.StartsWith("DeleteButton_"))//Is action?
    {
        SomeData=int.Parse(Action.Substring("DeleteButton_SomeData".Length));
        //Do something...
    }
    //Erase Action field not to fire action next time accidentially
    hfPostBackAction.Value=string.Empty;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-02
    • 2016-08-02
    • 2013-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    相关资源
    最近更新 更多