Button in CustomControl added in OnClick doesn't postback until second click - asp.net

I have the following scenario:
UserControlA contains a <asp:Button id="bSomeid" onClick="AddItem" /> with some code to an item to a shopping basket in AddItem.
UserControlB contains some LinkButton's that dynamically add a selection of UserControlA to the page in the OnClick event.
This is all done in an UpdatePanel. It is a little more complicated but I have pruned the information to what I believe is causing the problem, I will add more information if necessary.
The problem I have is that it takes 2 clicks for the AddItem event to trigger after I have added the items to the page after clicking the LinkButton.
I understand why this is happening - it is to late in the page cycle to register events for the next post back in the onclick - but can anyone think of a way around this? Can I force an event to be triggered on the next postback? I have tried to think of a way to run my code in page_load but I requuire access to the sender in the onClick.
Using .NET 4.0.
EDIT
I managed to find a way to get the link button sending the request in the Page_Load (using Request.Form["__EVENTTARGET"];) so I moved my code to the Page_load event. It still requires 2 clicks so I am assuming it isn't something to do with the onClick being registered to late.
Are there any other general things to check that could cause a button to require 2 clicks to post an event properly?

If your suspicion about being late in page life cycle is true then you can try using ScriptManager.RegisterAsyncPostBackControl method to register dynamically added controls in the link button click - considering that your button is within user control, you need to add public method into UserControlA that would actually register the button bSomeid1 and link button click from UserControlB would actually call the A control's method.
EDIT :
Another cause for button click not happening can be that button being dynamic control is not added in the page hierarchy when post-back happens (or it gets added very late in the page life cycle when the post back data is already processed). A really full-proof solution should add dynamic controls back to the page hierarchy in page_load it-self (and strictly maintaining same controls ids within hierarchy). If that's not possible then you can sniff the request (Request.Form) to detect the post-back.
In your case, you should ascertain if the button is indeed causing the post-back on each click. If yes, what is the POST data (Request.Form) for the first request - what is the __EVENTTARGET value on the first click (and post-back)? That should start your trouble-shooting.
On the other hand, a simple work-around could be to use html anchor element (you can still use link button) and have a javascript handler in the click event that would set some hidden variable and then submit the form (you can simulate the click on hidden button to trigger ASP.NET client side submit pipeline) . Now the hidden variable value can be used on the post-back to determine which link button has been clicked.

"Are there any other general things to check that could cause a button to require 2 clicks to post an event properly?"
Does it require two clicks on the control, or does it take accept a single click elsewhere on the screen, and then fire first time with a single click on the control?
I have my own (similar) issue with the Updatepanel where the first (expected) trigger does not fire and it seems that a single click elsewhere, and then the subsequent triggers fires first time (which totals 2 clicks)
[edit] Since you are working on this ATM, it may help me as well. Do you have a textbox with a trigger event on it? I do, and if I leave this blank (so that it does not fire) then there is no need for a second click.

Related

How can I handle a button event that triggers user control creation?

I have an ASP.NET web form on which I'm displaying a list of database items via user controls, generating the user controls dynamically - working fine.
Also on the page, I have an asp:dropdownlist filled with items that can be added to this database list. Along with this dropdown I have a button 'ADD'. My intent is that the user chooses and item, clicks add, and then the list of user controls on the form will include this new item.
I have all this working.
My issue is that the user control has a button 'DELETE', which removes the selected item from the list. That works, EXCEPT when I add a new item. Because my 'add' button event is always fired after Page_Load, even if I regenerate the list of user controls, the internal user control click events won't fire because the controls weren't created as part of Page_Load.
I need to know what I'm doing wrong, or best practices here, any advice. I tried to be precise in the description of the problem, but if I've not succeeded, let me know and I can add more details.
SIMPLE RESTATE: I need to know how to add a dynamically created user control to a page via a page button click event, and still have the user control internal click(etc) events firing.
Thanks for any help.
EDIT: Based on the feedback from the gentlemen here, and doing some further research related to their suggestions, I ended up implementing a solution based on what's presented on this page:
http://ryanfarley.com/blog/archive/2005/03/11/1886.aspx
Here's a snippet showing how I dealt with this. This snippet resides in my PreInit event handler. Not exactly an elegant weapon for a civilized age, but sometimes a blaster is all you've got to use.
'Look to see if button for adding a new client number has been
'clicked. If so, call the sub to add the item NOW, so that it
'is able to have it's internal click events fire.
For Each control_string As String In Request.Form
Dim ctl As Control = Page.FindControl(control_string)
If (ctl IsNot Nothing) AndAlso (ctl.ID = "cmdAddClientNumber") Then
Me.AddClientNumberToList()
Exit For
End If
Next
On the button handler, you initially add the UserControl to the Page. OnPreInit (which will next be fired when the user clicks Delete on the UserControl), you should re-add the UserControl - so that it exists, and can handle the Delete button event.
You will need to devise your own state tracking mechanism to determine that you need to add the UserControl during PreInit. I generally use ViewState, as evidenced by this seemingly similar post.
Similar question:
How to create and use custom control with UpdatePanel added to the page programmatically
Dynamic control should be re-added to the control tree OnPreInit, see documentation:
PreInit - Create or re-create dynamic controls.
ASP.NET Page Life Cycle Overview

ASP.NET Life-cycle Dichotomy: Dynamically Added Controls and Events

The situation:
I have user controls with buttons that have hooked events. Controls with events need to be initialized in Page_Load or earlier.
I wish to spawn these user controls dynamically by clicking an Add button.
It is important to remember that events, such as click events, are not fired until just before Page_LoadComplete.
Broken Solution A:
Page_Load: Dynamically create an Add button, hook click event.
User clicks on the Add button, triggers postback.
Page_Load: Creates the Add button as usual, and hooks click event.
Page_Load: Doesn't know that the Add button has been clicked yet, so it doesn't know to spawn the user control!
AddButton_Click: Page finally aware that a new user control should be added upon the next Page_Load.
User cannot see the control they added, because another Page_Load has been triggered.
User reloads the page by clicking a button, refreshing the page, etc.
Page_Load: Creates Add button, and hooks click event. Now aware of added user control, creates user control. Hooks events within the user control.
User clicks on button within user control, triggers just fine.
Result: User has clicked to Add a new user control, the server is aware that the control should exist, but the user does not see it until they trigger the page to load again (by clicking another button, or refreshing, etc).
Naturally, I took a look at the life-cycle, and see that Page_LoadComplete occurs after events, so if I place any event-dependent code in Page_LoadComplete, all should be well?
Broken Solution B:
Page_LoadComplete: Dynamically create an Add button, hook click event.
User clicks on the Add button, triggers postback.
Page_LoadComplete: Creates the Add button as usual, and hooks click event.
AddButton_Click: Page aware that a new user control should be added upon the next Page_LoadComplete.
Page_LoadComplete: Aware of the button click, dynamically adds the control, with its own internal button click event.
User clicks on button within the added user control, but it does not trigger!!
Result: Everything works great, except the button within the added user control is inert.
The conundrum is: I need controls to spawned by a button click, which means I need to put my Controls.Add(...) code in Page_LoadComplete. Inversely, I need the controls being added to have working events, which means the Controls.Add(...) code need to be in Page_Load. I have a perfect dichotomy.
The only janky solution I can think of is taking solution A and forcing the page to reload manually after clicking the Add button, which is a waste of bandwidth and processing.
This might not be the best practice, but you can check Request.Form for the evidence of add button click during the Page_Init event and add the controls there. It should solve your problem.

Why event bubbling and why not directly subscribe the click event?

I was going through an article on event bubbling in asp.net and came to know that although it is possible to subscribe to the click event of a user control's button from the containing page, "doing so would break some of the object oriented rules of encapsulation". A better idea is to publish an event in the user control to allow any interested parties to handle the event.
My question is that exactly how does a direct subscription to the button's click event from a containing page would break the object oriented rules of encapsulation?
Apologies if its a dumb question. :|
Thanks!
The Button is supposed to be encapsulated by the UserControl.
If the Page binds directly to events on the button, then the page is now dependent on the inner workings of the UserControl.
The Page should be consuming the UserControl, not the UserControl's button. If the author of the UserControl later wants to remove the button and use some fancy new method of firing its "Submit" event, your page could be broken because the button may no longer exist.
For that matter, if the owner of the UserControl decides in v1.1 to rename the button from btnSubmit to SubmissionButton, it could break your page, as well.
Better to consume the UserControl and let it be concerned with its own inner workings.
The idea is that the button of the control is an implementation detail of the UI of the control. If you republish the click event you could reimplement that button as an ImageButton, LinkButton, etc.
I think it's OK to attach an event handler at the page level to the button if the button is a permanent fixture of the UI. It saves a lot of event code, especially with a lot of buttons.

Please help me understand AutoPostBack property of an ASP.NET control

I'm learning about ASP.NET, mainly by following through a book, but also making an effort to actually do things along the way. But, I came across an explanation about list controls which I don't understand. This is what it says:
"[in the context of the Smart Tasks panel]...the last option sets the AutoPostBack property of the control. With this option checked, the control will submit the page it's contained in back to the server as soon as the user chooses a new item from the list"
Can you explain this statement for me? Thanks in advance for your help.
For normal client controls (such as a list control with AutoPostBack set to false), when a user chooses an item in the list, the browser does not communicate with the server. There's no network traffic and no delay for your user before they see the results of the choice, but there's also no opportunity to do anything in your server code, like calculate dependent values. If you want to do anything to the screen in response to the choice, you have to use a client-side script.
When AutoPostBack is set to true, selecting an item in the list sends a message to the server (via an HTTP POST). ASP.NET then executes whatever code you have attached to the list's changed event, rebuilds the page, and sends the revised page to the client.
If you set AutoPostBack="true" on a control, when it's value changes, it will automatically postback to the server.
For example if you wanted a dropdown that when changed displayed different data in a table below or something, you might want to postback get the new value so your page could refresh the data.
This is opposed to style of the dropdown and a button beside it you click to postback, so instead of change value, click the button, you can just change the value with AutoPostBack="true".
A ListBox has a SelectedIndexChanged event that you can handle to detect when the selected item in a ListBox has changed. You'd configure it like this:
<asp:ListBox ID="ListBox1" runat="server" OnSelectedIndexChanged="ListBox1_SelectedIndexChanged"/>
protected void ListBox1_SelectedIndexChanged(object sender, EventArgs e)
{
// Do something
}
With AutoPostBack="false" (the default), that event handler doesn't actually happen on the server in "real time". The user has to perform an unrelated action to submit (POST) the form, such as clicking a button, to make that event fire on the server.
If you want to take "real time" action on that event, you set AutoPostBack="true" which makes the form automatically submit every time the selected item is changed.
The benefit - you get "real time" notification of events. The drawback - the page talks a lot more to the server, so each click costs bandwidth and causes client "lag".
Further reading: http://www.dotnetspider.com/resources/189-AutoPostBack-What-How-works.aspx
When a user selects a ListItem (or whatever the collection item is), the page should automatically submit the web form to the server with a POST event.
here's the wikipedia page on HTTP POST events
http://en.wikipedia.org/wiki/HTTP_POST
The responsibility of an asp.net control contained in a Page is to render a part of the html that the user will end up seeing in his browser. Some controls support the AutoPostBack property. What it does is that it makes the control emit some extra javascript that will submit the form whenever the value of that control is changed, so that you can react to this on the server side.
Basically AutoPostBack is used so that whenever there is some change in the controls text or anyother change in the controls property, the page is submitted to the server.
Posting the page means, the page is submitted to the server. Suppose i use a textbox and i make its AutoPostBack = "true", now i write some text into it and click outside the textbox, then the page will refresh.
This refresh indicates that your value which you entered into the textbox has been submitted to the server.
The postback is handled by ASP.NET server. AutoPostBack will automatically post back your page to the server.
Add an event Handler. This will give you a better picture.
In your case of DropDownList: Add an eventhandler: double click the DropDownList, it will route you to an eventhandler:
Write something in that event handler let us say : Response.Write("message");
The page will refresh and you will see your message, this means the page was posted to the server and the server has executed your event handler and displayed you the message.
I hope this was usefull

ASP.NET page events - Button click event comes after GridView bind

My understanding of the order of page events is this:
Page : Load
Control : DataBind (for a GridView or whatever)
Control : Load
Control : Clicked (for a Button)
Page: PreRender
Control : PreRender
(There are lots of others - but these are the ones I'm interested in)
The important thing to notice here is that the button's click event comes after the gridview's bind event. If the button causes a change to the data, the GridView displays the old data. I could rebind the control in the PreRender event, but that seems totally ugly.
This must be a very common pattern (a button that updates data). How do I put this together so that the GridView binds to the data after the Button click changes it?
The answer was in the Button Click event, after the data has been changed, call DataBind() on the page to cause the GridView (and anything else that needs it) to rebind. I didn't realise you could do that.
Thank you Ocdecio & Mufasa - I would mark your answers as helpful, but I got no rep yet.
ASP.NET does, by default, lots of binding and rebinding. Rebinding after a click event is normal.
The only reason the button click event comes after GridView bind is because you programmed your page to do that . I don't see any problem in binding the control in the PreRender event, in fact that is the only way to take action after a control event (such as Button onclick).

Resources