ASP.NET dynamic Command Button event not firing

23,250

Solution 1

Essentially you need to create the original controls once on page load in order to be able to handle the button click, you then need to clear the controls and re-generate them either in the button click handler or as you have done on pre-render - i think it is cleaner on the click handler, so you need the same code in both (preferable refactored out to a separate method)

The example below would mean minimum code changes for you:

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

Solution 2

You have to wire it up like this (in C#):

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

Alternatively you can inject the attribute --> onclick = "Button_Clicked" like this:

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

If you want it in VB.NET go to this page and knock yourself out - I could do it for you but what's the point :)

EDIT: keep in mind you'll have to re-wire the event-handler (as shown above) every page-load.

EDIT: OK - I see the problem now that you added the rest of the code. You are wiring up the event handler on pre_render. Event handlers are executed just before load_complete, which happens before pre_render. This is why you event_handler doesn't execute: you're adding it too late in the page lifecycle. Put that code in the page_load routine and it should work.

Solution 3

I had this same problem, I was loading the controls just fine. the events were firing the first time, but not the second time. The problem was I didn't have a unique identifier tied to the controls. So I added a unique ID field to the control I was adding to the page, and it worked just fine, every click.

Share:
23,250
Chris
Author by

Chris

Updated on July 05, 2022

Comments

  • Chris
    Chris almost 2 years

    I'm trying to create Command Buttons dynamically, but clicking the button in question doesn't seem to raise the corresponding CommandButton_Click event. I noticed that in the examples on SO a property is set for Button.OnCommand as well as the CommandName and CommandArgument but it isn't an option in intellisense.

    So the question is, what am I doing wrong here (code below without the OnCommand), is it accessed in some other way - if so, why do the examples I've found all show it as .OnCommand?

    EDIT: Further to help, I have added the handler however the event is still not firing. The buttons reside in an UpdatePanel and are rebuilt on every postback (along with the handler). I have created a simplified example of what I'm doing which is shown below If the button event fires, it writes "EVENT FIRED" to the txtTestFired Textbox - suffice to say I have never seen that. This is really driving me nuts, any help is very gratefully received.

    .aspx file

    <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 file

    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
    
    • JohnIdol
      JohnIdol over 14 years
      see the edit in my answer in reply to your edit
    • Chris
      Chris over 14 years
      Moved to page_load and the event fires...BUT...now a different problem (this is why I put it in pre_render originally). The button click event (to add the textbox etc) is happening after the Page Load in the page lifecycle. Therefore when I add this to my test I get the problem that the system is always one postback behind - ie you have to submit twice before the first set of controls are rendered.
    • cargo8
      cargo8 over 14 years
      I think your original problem is solved correctly (the event not firing) - your current problem should probably be added as a separate question. sounds a bit like you may be addeing new controls too late, are you re-directing during the click handler?
    • Chris
      Chris over 14 years
      Thanks, the event is still not firing in the context of what is needed. If it is impossible then sobeit, but I would rather continue the question in context ahead of creating a near duplicate question. The crux of the problem is that a user clicks a button which creates controls. The controls don't know they need to be created in page_load because the button click event is yet to be handled. There is a quick and dirty fix where a fake postback or reload is done after every submit but that is clunky and nasty.
  • Admin
    Admin over 14 years
    This is C#, its not how you do it in VB.NET
  • JohnIdol
    JohnIdol over 14 years
  • San Jacinto
    San Jacinto over 14 years
    god help your clients if you can't take 13 seconds and figure out the minor syntax differences on your own.
  • JohnIdol
    JohnIdol over 14 years
    I see you took the time to do that in your answer ... talk about practice what you preach :)
  • Chris
    Chris over 14 years
    Thanks - I have put this in and it still won't fire! I'm now wondering whether it is because the button is being created within an UpdatePanel - could this be the case in your knowledge?
  • Chris
    Chris over 14 years
    Thanks - that convertor tool is pretty handy too. Would being in an update panel affect the ability of the button to wire up?
  • JohnIdol
    JohnIdol over 14 years
    If you're trying to update an update panel by clicking the button then you need to setup the button as a trigger for the update panel. If the button is in the update panel it shouldn't be a problem (the update panel should refresh and your code behind should execute). but maybe I am missing something, updating your question showing the markup (with the update panel) would probably help.
  • Thomas
    Thomas over 14 years
    You need to recreate the button on every Postback. Otherwise the events won't fire.
  • JohnIdol
    JohnIdol over 14 years
    Correct - I was assuming that (shouldn't have). Are you re-wiring the event-handler every time the page loads?
  • San Jacinto
    San Jacinto over 14 years
    @Johnldol Actually, I was referring to Chalkey's comment about the answer not being in VB. My point was that "If you can't port something this minor from C# to VB, then there are larger probles you have to solve than getting your event to fire." It was more of a tongue-in-cheek comment. I think you personally went above and beyond posting a converter. I'm actually the only one currently who has voted for your post...
  • Chris
    Chris over 14 years
    Thanks - I have now added a full code listing as this is still giving me grief - really appreciate your help.
  • Chris
    Chris over 14 years
    Thanks - I moved it to page load and the event fires...BUT...now a different problem (this is why I put it in prerender originally). The button click event (to add the textbox etc) is happening after the Page Load in the page lifecycle. Therefore when I add this to my test I get the problem that the system is always one postback behind - ie you have to submit twice before the first set of controls are rendered. Any ideas on this!? Thanks again for your help.
  • Chris
    Chris over 14 years
    Thanks - I'll give this a whirl
  • Chris
    Chris over 14 years
    Thanks - slight variance on your approach based on my actual needs - what I have is a counter that creates n+1 Command Buttons then clears them for the add/remove that may result from a button click (either add another, or remove one) - that way I will never have more than a +2 surplus of handlers floating around which was a concern. Working like a dream - thank you.
  • JohnIdol
    JohnIdol over 14 years
    nice timing :) - I would maybe store a counter in the ViewState rather than a DataTable in session?
  • Chris
    Chris over 14 years
    the problem I found with ViewState is that if the user refreshes the page, the controls are lost (there are about 6 controls per row) - the form may take them a while to build so it would be a bit of a tear-your-hair-out moment for them if the entered data didn't persist on a refresh. Thanks again for all of your help along the way (+1 rep btw on your answer, sorry I can't give more)
  • cargo8
    cargo8 over 14 years
    +1 for all the work you put in - apologies for hijacking your effort.
  • JohnIdol
    JohnIdol over 14 years
    @dice cheers - you spared me the bother of a further edit to my answer :)
  • Henrik Andersson
    Henrik Andersson over 11 years
    Could you please elaborate on this answer with some code perhaps?