Dynamically Change User Control in ASP.Net
Asked Answered
A

4

11

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?

Abib answered 12/6, 2009 at 16:34 Comment(0)
C
6

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.

Clytemnestra answered 12/6, 2009 at 16:44 Comment(6)
How do you determine the string for Request["MyDropDownID"]?Abib
DropDown1.UniqueID What a noob!Abib
Yes! This worked! Thank you thank you thank you! I feel I should point this out for others... ASP.Net is super finicky. After following womp's Request method, if I did OnInit() { PlaceHolder.Controls.Add(oldcontrol); PlaceHolder.Controls.Clear(); PlaceHolder.Controls.Add(newControl); } ...It didn't work. If I do: PlaceHolder.Controls.Add(newControl); ...Then it does work! Hurray!Abib
+1 for the Request[...] suggestion. I was going crazy over this until now.Nipha
+1 For the Request[...] suggestion from me too. Many thanks.Parsec
Saved my life, hair were in danger :-)!Straiten
B
11

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.

Blew answered 12/6, 2009 at 16:44 Comment(4)
Unfortunately, this is already what I have it doing. (The SelectedValue is a property that causes the value to get stored in session.) The problem is the newly created control isn't getting saving changes on the next postback.Abib
This is because ViewState has not been saved for the new control ID, and ViewState is not expecting to see it. You need to have your control registered with ViewState - I would suggest my solution #1, or else what Joel suggests about adding all controls and making them invisible. Remember that setting Visible=false means nothing is rendered - so this is usually a good solution if the number of controls you have is manageable.Clytemnestra
+1 for preventing further loss of hair. All I had to do was switch one of my persisted values to be stored in Session rather than ViewState and as if by magic it started to work!Chainplate
when This is just an archive comment to add to what @Abib experienced. If you are not careful always explicitly setting the same control ID for the controls that is recreated then the exact issue he describes might occur (when building as Joel describes above with oninit / event).Heppman
C
6

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.

Clytemnestra answered 12/6, 2009 at 16:44 Comment(6)
How do you determine the string for Request["MyDropDownID"]?Abib
DropDown1.UniqueID What a noob!Abib
Yes! This worked! Thank you thank you thank you! I feel I should point this out for others... ASP.Net is super finicky. After following womp's Request method, if I did OnInit() { PlaceHolder.Controls.Add(oldcontrol); PlaceHolder.Controls.Clear(); PlaceHolder.Controls.Add(newControl); } ...It didn't work. If I do: PlaceHolder.Controls.Add(newControl); ...Then it does work! Hurray!Abib
+1 for the Request[...] suggestion. I was going crazy over this until now.Nipha
+1 For the Request[...] suggestion from me too. Many thanks.Parsec
Saved my life, hair were in danger :-)!Straiten
D
1

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

Debauchery answered 12/6, 2009 at 17:40 Comment(0)
H
-4

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.

Hercegovina answered 12/6, 2009 at 16:41 Comment(5)
No! Don't add dynamic controls during page load. That's already too late.Blew
This won't solve the problem. Page_Load() still occurs after ViewState is loaded.Clytemnestra
is that ASP.Net 1.1 by any chance?Clytemnestra
btw..this will load posted values, but it won't load state.Clytemnestra
Originally yes, now it's in 3.5. You may be right about state, I only care about the values... (rewriting the whole thing with dynamic data anyway, seems to manage the whole situation better)Hercegovina

© 2022 - 2024 — McMap. All rights reserved.