2009-11-21 99 views
4

我试图动态地创建命令按钮,但单击有问题的按钮似乎不会引发相应的CommandButton_Click事件。我注意到在SO的例子中,一个属性被设置为Button.OnCommand以及CommandName和CommandArgument,但它不是intellisense中的一个选项。ASP.NET动态命令按钮事件没有触发

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

编辑:进一步的帮助,我添加了处理程序,但事件仍然没有解雇。这些按钮位于UpdatePanel中,并在每次回发时(与处理程序一起)重新构建。我创建了一个我正在做的事情的简单示例,如下所示如果按钮事件触发,它将“EVENT FIRED”写入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 
+0

请参阅我的答案中的编辑以回复您的编辑 – JohnIdol 2009-11-23 10:29:28

+0

已移至page_load并触发事件...但是...现在出现了另一个问题(这就是为什么我最初将它放在pre_render中)。按钮单击事件(添加文本框等)发生在页面生命周期中的页面加载之后。因此,当我将其添加到我的测试中时,我得到的问题是系统始终是一个回传 - 即在呈现第一组控件之前必须提交两次。 – Chris 2009-11-23 19:32:24

+0

我认为你的原始问题可以正确解决(事件不会触发) - 你当前的问题应该作为一个单独的问题添加。听起来有点像你可能加入新控件的时间太晚了,你是否在点击处理程序中重新定向? – dice 2009-11-23 19:47:19

回答

4

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

下面的示例将意味着您的最小代码更改:

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 
+0

谢谢 - 我会给这个漩涡 – Chris 2009-11-23 20:38:22

+0

谢谢 - 根据我的实际需要,你的方法略有差异 - 我有一个计数器,创建n + 1命令按钮,然后清除它们的添加/删除,可能会导致按钮点击(或者添加另一个,或者删除一个) - 这样我就永远不会有超过+2的处理程序过剩,这是一个值得关注的问题。像梦一样工作 - 谢谢。 – Chris 2009-11-23 21:02:13

+0

不错的时机:) - 我可能会在ViewState中存储计数器而不是会话中的DataTable? – JohnIdol 2009-11-23 21:54:29

6

你必须连线起来像这样(在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例程中,它应该可以工作。

+0

这是C#,它不是你如何在VB.NET中做的 – 2009-11-21 15:46:35

+0

你去这个URL - > http://www.developerfusion.com/tools/convert/csharp-to-vb/ :) – JohnIdol 2009-11-21 15:47:49

+0

上帝帮助你客户端,如果你不能花13秒钟,并找出你自己的小语法差异。 – 2009-11-21 15:53:04

0

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

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 

希望这有助于...

+0

谢谢 - 我已经把它放进去了,它仍然不会开火!我现在想知道是不是因为该按钮是在UpdatePanel中创建的 - 在您的知识中可能会出现这种情况吗? – Chris 2009-11-21 16:01:32

1

我有这个相同的问题,我加载控件就好了。事件首次发射,但不是第二次。问题是我没有一个与控件绑定的唯一标识符。所以我给我添加到页面上的控件添加了一个唯一的ID字段,并且每次点击都很顺利。

+0

您能否请详细说明这个答案与一些代码也许? – 2012-12-10 21:45:05

0

正确的方法是:

  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; 
}