Odd Behavior with Viewstate on Dynamically Loaded Control - c#

I am dynamically loading user controls to switch between views in my project. I am aware that I need to reload my user control on every postback. The odd thing is my viewstate for the control is maintained even though the control is gone? I confirm that the panel I loaded it into is empty and then I check the view state and my value is there.
What's stranger is that if I load a different control, it can see the viewstate from the previous control? I checked and my page cannot see viewstate from my dynamically loaded control and visa versa. This makes me think the user control is treated as its own page. The confusing part is why the second view I load can see values from the first and why the values are there even though I the control has disappeared?
I also find this section of the code to be useless. Why is it removing the control? The panel is always empty (the code is from Telerik):
string controlId = LatestLoadedControlName.Split('.')[0];
Control previousControl = pnlControlPlaceholder.FindControl(controlId);
if (!Object.Equals(previousControl, null))
{
this.pnlControlPlaceholder.Controls.Remove(previousControl);
}
I looked at several posts and most say that viewstate is lost on every postback, although this is not the case for me. Perhaps because I'm using update panels. Although if an intial request handles an event and then reloads the same control again, the viewstate is lost. It only seems to preserve the viewstate on the very next postback.
Can anyone explain this odd behavior of sharing viewstate between user controls or why it is there even though the control is lost?

Apparently you can read viewstate between pages in two scenarios... Cross page postback and when using Server.Transfer. I believe the cross page postback scenario would explain what I am seeing.

Related

ASP.NET Dynamic user controls save data issue

Here is what I have
A set of business entities that resides in the session (for example, Employee:{"Name":string,"Surname":string,"Salary":double, "Position":enum}
A set of user controls (using Telerik.Web.UI), each of it describing a business entity (for example, EmployeeControl.ascx:
RadTextBoxes for Name, Surname and Salary and a RadComboBox for Position. There is also a RadButton in the control, which saves the data that is entered in the controls client-side to a certain entity, which is already known by the time the control is loaded).
A page with a RadTabStrip and RadMultiPage, which is used to render different controls in different tabs
The target RadTab that hosts our Employee control.
So, the issue is: when I hit the Save button, a postback is done, thus clearing my controls and only after that the Click event is fired. I have tried to avoid it by using RadAjaxManager with a OnClientClicking script with canceling the postback, but with no success, because a postback is still generated, although its __EVENTTARGET is RadAjaxManager itself.
Basically, this is what happens:
The user selects a tab with the Employee control with it. The control is filled with initial data on Page_Load. (A postback occurs with re-creating my controls)
The user modifies the data. (Nothing happens, no control generates postback)
The user clicks save. (A postback occurs with re-creating my controls, then a Click event is fired)
No data is saved
When the data is entered again and the save is called, everything is saved as it should.
How can I make this work correctly?
P.S. I was able to achieve the required result (although not completely: the screen "flickers" when a postback is done) by dividing the postbacks into odd ones and even ones (I added another variable in Session named PostCounter, which is incremented every time the page is posted). So, when an expression PostCounter % 2 is equal to 0, I perform another postback by executing __doPostback with its eventTarget parameter being the ClientID of an instance of a RadAjaxManagerProxy, and the argument being just some string that does not match any that is used in my regular Ajax requests.
Make sure your controls always have the same IDs when recreated. Imitating postbacks from other controls should not be needed, the buttons are IPostBack controls so things should work nicely.
This (one AJAX, one full postback) behavior is typical for Sharepoint where you need to add AJAX settings programmatically: http://www.telerik.com/forums/radajaxmanager-in-webpart-on-sharepoint-2010
Also, make sure you do not nest AJAX settings (from a manager and/or proxy), RadAjaxPanels and asp:UpdatePanels: http://www.telerik.com/help/aspnet-ajax/ajax-controls-in-ajaxpanel-and-ajaxsettings.html.

ASP .Net - Change/Update Dynamically Created Textbox

OK, got pretty far on this one, but need an assist from someone with superior ASP skills. I'm using code behind to populate an ASP table with the results of a SQL query. The read-only values are stored in the .text of some of the table cells, while read-write values are stored in .text of textbox controls (dynamically created and added to table cells.)
This works fine on the first load. When the page reloads with a different query (for example: a user selects a different column to order by,) the table cell values repopulate correctly, while the textbox values remain unchanged. Throwing in a table.rows.clear() prior to the query does not seem to fix this.
More info:
I created a method to wipe all textbox.text values using table.findcontrol(). When tied to a button, this method works to spec (which indicates findcontrol is able to find/update the textboxes,) though all affected textboxes remain the blank if the page is reloaded. If placed in the page load, the method does nothing (textboxes retain their former values.) In debug mode, findcontrol pulls a value when used on the button, but comes up null when added to pageload. I have done this with table.rows.clear() commented and uncommented.
I have also attempted to throw all the code into oninit. This doesn't seem to make any appreciable difference.
Dynamic controls must be added on each page request, preferably during the Init event. It sounds like you are not recreating them on time.
Add them on every single page request and, as part of the page life cycle, they will receive their values from the viewstate
In order for dynamic controls to retain their values you need to:
a.) Ensure Viewstate is enabled for the page.
b.) Recreate the controls on every page load ensuring you create the controls with the same IDs as were given to the controls originally. Also you need to do this before the viewstate is loaded (preferbly in the Onit or PreInit method. See the page life cycle here: http://msdn.microsoft.com/en-us/library/ms178472%28v=vs.100%29.aspx

Dynamically add and remove a User Control from a Page

I have a Web User Control that I need to add to a page simply in order to add it to an HtmlForm so I can send an email with this User Control, however, I do not need this Control to appear on the page, I just need it to fill with data so I can send this email, and then be removed so it does not appear on the page.
Currently I have tried:
myControl c = new myControl();
c.InitializeAsUserControl(Page);
c.fillInfo(data);
//add to email form and send email
yet this adds the control to the current page on post back once the email has been sent and a confirmation message
I have also tried
myControl c = (myControl)Page.LoadControl("~/filename.ascx");
//send email
Page.Controls.Remove(c);
yet this also renders the control on the page and does not remove it. I have tried to add it to a panel and set Visible to false, but unfortunately this does not work either. If I simply create a new myControl() without rendering on page or calling LoadControl I get exceptions thrown when fillInfo is called when it tries to modify asp:labels in the User Control saying that the objects are null or not instantiated.
Which part of the page cycle are you loading and unloading the controls? To work properly it needs to be done in Page_Init. It's a common mistake to do it in Page_Load. If it is added anywhere else other than Page_Init it won't be added to the ViewState correctly and problems will ensue.
Rather than unload - I would add it to a Panel and set Visibility to false. Could be the reason that isn't working for you at the moment is that the control is being added at the wrong part of the page cycle and isn't being added to ViewState correctly.
Could that be your problem?
I suggest reading the entire TRULY UNDERSTANDING DYNAMIC CONTROLS series. To successfully use dynamic controls with postbacks, viewstate, bindings, and the other WebForms features, you really have to know the page and control lifecycles and their interactions inside out.
When you load and set ViewState depends on the cycle. ViewState is loaded between Page_Init and Page_Load, so the control has to be in Page_Init. However, any processing based on auto-loaded ViewState, needs to go in Page_Load. Where/when ViewState is enabled depending on the control hierarchy can also affect this. I suggest you read that guide above in depth if you really want it to work. Or, you'll have to post your entire control code and its use in a page for us to tell you which parts you are missing or have in the wrong part of the page lifecycle.
I've made dynamic controls work, but 99% of the time, unless the control is extremely trivial, it's easier to find a different solution than it is to make sure all the interactions work correctly with dynamic control creation.

Reloading a custom control

I have a cs class which I use as a control on one of my page. It is like a table with some values. This control is loaded when the page loads. After user does some selection, I need to refresh this control with the new values which I do by assigning it in code behind. My problem is that though I am reassigning some properties, the control which was loaded on the page load, does not refresh, which makes sense. i have tried a few ways but could not figure it out. I am posting it here as I am running short of time and would appreciate it if anyone can point me to the right direction.
Thanks.
Make sure you are calling LoadControl on PreInit and doing so on each postback.
PreInit:
Use this event for the following:
Create or re-create dynamic controls.
....
ASP.NET Page Life Cycle Overview

When to use PreRender over PageLoad?

Related question: Get All Web Controls of a Specific Type on a Page
In the question above I asked how I can get all controls, works like a charm but something just doesn't quite fit so I thought it might be me. I have the following code but it's not manipulating the controls on the page but in my theory it should work.
List<DropDownList> allControls = new List<DropDownList>();
ControlEnhancer.GetControlList<DropDownList>(Page.Controls, allControls);
foreach (DropDownList childControl in allControls)
{
foreach (ListItem li in childControl.Items)
{
li.Attributes.Add("title", li.Text);
}
childControl.Attributes.Add("onmouseover", "this.title=this.options[this.selectedIndex].title");
}
Thats the code, GetControlList() code you can get from the related question which shows how it gets all controls, its just my manipulation. I am trying to get all dropdownlist listitems and add a title to them so I can have a tooltip.
It's a quick fix for IE8 and below which cuts of long text in drop down boxes.
Page_Load happens often too soon; Page_PreRender is the last moment before the page's HTML is actually rendered for the browser and in many cases is the best place to set attributes on user controls.
This because during the web form (page) life cycle there are other events in the page (and in the user controls contained in the page...) which sometimes remove/replace/overwrite (really) those attributes so the only way you can get those attributes to the browser is to append them after all other life cycle events have been fired and handled, in the Page_PreRender.
Actually, even PreRender might be too early in some cases (e.g. you could have DropDownList controls added to the control tree during databinding of controls that use DataSourceID).
There are two further events that might be more appropriate:
PreRenderComplete. At this point, all controls are created and the page is ready to render.
SaveStateComplete. Occurs after view state and control state have been saved. Any changes you make here won't be persisted to view state.
In your example (adding client-side attributes), I'd use the SaveStateComplete event to avoid unnecessary view state bloat.

Categories