I want to add a user control when the user clicks on a button (the server-side event).
I'm able to dynamically add the control but since it's too late on the page life cycle the events on that user control won't fire (in this specific case, a button in that user control).
All solutions I've seen regarding this is to add the control on Page_Init (or Page_Load) something that I can't do here, also the control must stay "dynamic" so I can't just hide it and then make it visible.
The problem here was the fact that the IDs of such controls were auto generated and asp.net matches the events of the controls by ID.
I fixed this by giving a ID to each dynamic control after they are created.
Control control = LoadControl("~/Controls/" + controlName + ".ascx");
control.ID = "SomeId";
parentElement.Controls.Add(control);
Related
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
I have a Panel. Now in that panel, i'm adding controls. It is getting added and displayed.The problem is when the page is posted back.I know the controls have to be binded again in the panel. But lets say if the user has entered some value in the dynamic created text box. Its is getting lost..
I have done this before by storing the data from the controls in session.
Every time you dynamically add a control, store the current data entered into the controls in session or viewstate for example, and then rebind on postback. Not the most elegant solution but it worked. I take it this is a webforms question?
Add dynamic control click
Save current form data
On page_load load the data from viewstate into the controls
Make sure that the controls get the same ID each time (for ex. by specifying an ID explicitly)
and you should add the dynamic controls on Page.Init so they can participate in the page's life-cycle.
There's an article on 4guysfromrolla.com, Dynamic Web Controls, Postbacks, and View State
I'm using Register at the top of the page to register an ascx control, now the thing is I want to use this control twice on the page.
Now, the problem is when I hit buttons of one instance of the control, it fires the validation of both of the controls, and it obviously breaks, because it should be validating only one control - itself! The reason I am sure about this is because if I keep only one instance of the control on the page, then it flows nicely.
What I already tried that did NOT work:
1)Putting the two instances in different ASP Panels.
2)Registering the control twice at top of the page, so each registration has only one instance on the page.
I would not like to modify the validation of the control itself, but it's a huge project and it is being used at other places, and I do not want to disrupt other things. FYI It's using "Page.IsValid" to validate.
Set the ValidationGroup property of the validators and the ValidationGroup property of the buttons dynamically in the Page_Load method of the user control. You can use the user control's ID property as part of the ValidationGroup to differentiate between the two controls.
e.g.,
myRequiredValidator.ValidationGroup = "valGroup_" + this.ID;
myButton.ValidationGroup = "valGroup_" + this.ID;
I have created user control container (panel actually) which dynamically adding and removing user controls items (like rows). Here is the problem: when the new user control is added to control collection get unexpectedly a value from the previous added control - only on the first post-back.
Detail description:
In the initial response I fill one user control item.
Then I click on the "Add" button, which adds new user control item to the panel, and this NEW control gets values from previous one (to be more even more confusing new control do not get all values, only form the disabled textBox control and dropDownLists). Why? The UC gets value on the server, when is added in the panel controls collection.
So my implementation with this problem was:
UcSomeControlItem uci = LoadControl("UcSomeControlItem .ascx") as UcSomeControlItem;
uci.DataSource = new SomeObject;
uci.DataBind();
uci.ID = IdPrefix + ControlID;
ph1.Controls.Add(uci);//At the end
When I changed the adding to the panel control collection sequence problem dissapear, sience the UC gets value on the panel adding ...
Like:
UcSomeControlItem uci = LoadControl("UcSomeControlItem .ascx") as UcSomeControlItem;
ph1.Controls.Add(uci);//Firstly adding ..
uci.DataSource = new SomeObject;
uci.DataBind();
uci.ID = IdPrefix + ControlID;
So I would like to know exactly what is going on? Who sets the value to the newly added created control?
As soon as you add a control to it's container when the container is already on the page, all the lifecycle events (Init, LoadViewState, Load, etc...) are fired sequentially for the newly added control, until it catches up to where the lifecycle of the parent control is currently at.
Because you set the ID of the control and then add it to the page, it has the same ID as some previous control when all the catch-up events are fired. So when LoadPostbackData is fired for the control (which occurs right after ViewState is loaded), ASP.Net assumes it's the same control as before simply because the ID's match, and proceeds to load the previous values into the controls.
When you change it so that you assign the ID after you added the control to the page, all the lifecycle events are fired when the control just has an auto-generated ID, so the postback processor doesn't recognize it as a control that existed previously.
Hope that's clear.
I'm trying to create a web page that will display an appropriate user control based on the selected value of a drop down list.
Basically the page layout is this:
Drop Down Selection
< User Control created based on drop down selection >
I have it half working... the controls are changing when the selection changes.
In OnInit(), I dynamically create the last selected control (whose value gets saved in session state because ViewState isn't available at OnInit).
When the drop down selection change occurs, I remove the old user control, and add a new one. The problem is: with the new control being added from the selection changed event, I'm not able to save changes from the user on the first postback. After the first post back, the selected control is created from OnInit instead of the Change event, and state is saved from then on, until the next selection change.
Here is the SelectionChanged method:
protected void SelectionChanged(object sender, EventArgs e)
{
SelectedValue = int.Parse(DropDownList.SelectedValue); //Store in Session
Control userControl = GetSpecificUserControl(SelectedValue);
PlaceHolder1.Controls.Clear(); // Remove old user control
PlaceHolder1.Controls.Add(userControl);
}
Any changes made to the new control by the user after SelectionChanged happens are not saved on the following post back. However, subsequent postbacks do get saved. At that point, the control is getting created in OnInit().
Is there some way to force the correct post back and ViewState when the control changes? Is it possible to force a page reinitialization after the control is changed?
What you need to do is keep the last known value of the DropDownList in the Session. Then:
OnInit:
Create whatever control is indicated by the saved value in the session
SelectionChanged Event
Remove whatever you created during OnInit
Create and add new control based on new DropDownList selection
Save new DropDownList selection in session
This way, on the next postback after a change you are re-creating the control that ViewState expected to find, and so it's state will be restored.
Dynamic controls can be very finicky. Often it is easier to create all of the controls you might possible need and set their Visible properties to false. This way they don't render to the browser at all. Then set Visible to true for just the controls you need when you need them.
This is the classic tear-your-hair-out problem with ASP.Net webforms. You have several options:
1) This is a bit of a hack, since it goes outside the intended page lifecycle a bit, but in my experience it's the most direct way of dealing with the problem. When the page posts back from the drop down selection event, simply poll Request["MyDropDownID"] for the selected value of the drop down control during Init() - don't wait for the OnMyDropDownChanged() event to set up your page.
2) Implement your own ViewState handling for your user controls. This requires digging into the ViewState documentation and overriding a number of methods.
3) Joel's solution. He beat me to it but I was trying to get first post :p
Other options involve posting values using javascript and such, but those get really messy.
If the list of options is not too big, you could just render all the user controls statically and use JavaScript/jQuery to show/hide the appropriate controls based on the value of the dropdown (onchange js event). You can use the dropdown value to extract the appropriate values from the user controls when saving.
You avoid the pain of dealing with dynamic controls, provide a more responsive UI when selecting from the dropdown (no postback), etc...
Don't add the control in the SelectedIndexChanged handler, add it during Page_Load. You'll just have to test the value of the dropdown each time the page loads, and load the correct control for that value.