I know there's a lot of information out there about how disabling ViewState will not prevent textboxes from persisting values across refreshes/postbacks. What I can't fins is information about how to circumvent this behavior.
Here's why I need to do this. I have a form that updates a db via AJAX. Every time a user changes a field, the db is updated immediately. Because of this, there's no reason to store values anywhere but the database.
Consider the following scenario.
User loads the page, textbox FirstName has a value of "Bob."
User changes first name to "Dave." (Database updates)
User clicks the refresh button.
We'd expect the FirstName box to now have the value of "Dave," but instead it shows "Bob." So how to force ASP to load the values from the db?
User clicks the refresh button.
On this step you'd re-read the data from the database and forcibly populate the controls with that data. If all of the "events" from the page are in fact handled by AJAX requests, then it sounds like the only two meaningful "WebForms events" are Page_Load and the Click handler for the "refresh" button. One of those two events should re-populate the controls from the database.
(Or is there no "refresh" button and the user is just reloading the page via browser functionality? In which case Page_Load should just always populate the controls from the database in this scenario.)
It seems the problem I was encountering had to do with creating and populating controls in during the correct page events. Fixed this by creating controls in Page_Init, and populating them in Page_Load.
Related
I have two Repeater controls, each hosted in a user control. Both user controls are contained in the same aspx page. Only one User Control is visible at any one time. The repeaters are comprised of checkboxes, and text boxes for user input.
The aspx page is configured with an Ajax ScriptManager; and contains several Ajax UpdatePanels. These UpdatePanels result in partial page post backs when text is changed in a textbox control in controls on the aspx page (this is not the behaviour for the Repeaters in the User Controls). Through use of several AsyncPostBackTriggers, various controls contained in the other UpdatePanels on the page have their content refreshed in response to the partial page post backs they are configured be notified about.
Depending on a radio button group selection, I set the visible property to true or false – as appropriate for the User control containing a repeater control. The Repeater control is then populated with data using databinding. All of this works.
However, when the Submit button is clicked, the Repeater control contains no data.
Given that I am not dynamically adding the Controls containing the Repeater controls (but using Visible true / false). I would have thought that the State of the fields and the data in the visible control would be preserved during the post back.
The User Controls are contained within the UpdatePanel that contains the Submit Button.
I have explicitly Enabled View state without any effect.
Am I correct in assuming that I should not have to do any explicit handling of data changes the user makes (via client side script and manipulation of an Data Structure Representing the Repeater Data); and the View State should maintain the data I need to access on the server when submitted?
I do not believe that it is the User Control visible state changes that are causing the issue because when the page is initially loaded on of the User controls is populated with dummy rows (so it displays).
I am suspicious that because the visible state of the controls is changed during partial page post back, that the Page View State ends up with no knowledge of the User Control and therefore cannot track its data (or changes).
I have investigated a lot of similar sounding posts but so far do not feel that I have come across a solid explanation that can help me understand and fix the issue.
Hopefully someone can help.
I must be the only person who was unaware of the finer points of DataBind() method; be it called on a specific control being bound to data; or on the page itself. I hope the below helps others who find themselves in a position where data binding appears to be inexplicably lost'.
My problem was that my page was pretty complex. It has several User Controls on it. The problem was that in these User Controls, I was calling Page.DataBind() in the Page_Load event handler to 're-bind' the page data on PostBacks. This resulted in the Repeater control located on another User Control, to lose its data binding.
Removing the Page.DataBind method call from each of the User Controls on the Page_Load event handler method resolved the problem. It had nothing to do with Update panels / refreshes etc.
I sort of answered my own question I think but I want to make sure I am understanding correctly. I initially thought that when a user provided values in a form, that on postback the values were submitted as part of the Viewstate, because TextBox.Text is part of the viewstate. Now I have found that user supplied values actually aren't applied to the controls until after the OnLoad event. This confused me because I thought that viewstate was loaded into the controls before OnLoad(or when calling Controls.Add()). I have gone over the documentation on page and control lifecycles a few times and I am just now realizing that there was a different step for handling postback data(this step didn't appear in a lot of documentation :(
1) So postback data, the values user's type into the fields, is applied after the OnLoad event, and Viewstate data is applied just before the OnLoad event?
2) So essentially all this means is that on postback the server gets two values for a TextBox.Text property, the one in Viewstate, which is like the "old" value from the previous request, and the new value supplied by the user in the form?
3) Does the .net framework apply postback data the same was as Viewstate, in that it finds the appropriate control via it's ID property? This is important because I am creating controls dynamically and I may even have forms that change structure overtime and need to think about how I handle ID's. So far I haven't been setting the ID property and everything works fine but things may be more complicated later on.
4) Does viewstate data ever get modified at all on client side? Or is the viewstate identical to what was sent by the server in the previous request(assuming no tampering)? My impression used to be that the server encoded all the control properties into the viewstate, and on the client side when the user submitted the form, the viewstate field was decoded, modified, encoded, and submitted to the server with modifications. I assumed there was a bunch of javascript doing all this for me. Now I think I had it all wrong. Instead it seems that the Viewstate never changes on client side, and all the client changes are in the postback data such that the next request the server loads viewstate, loads postback, and provides a new updated viewstate in the next response?
1) Both are loaded before Load
2) Basically, yes
3) ViewState is applied first, then Post Data
To quote Scott Mitchell(see below)
dynamically added controls must be
programmatically added to the Web page
on each and every page visit. The best
time to add these controls is during
the initialization stage of the page
life cycle, which occurs before the
load view state stage. That is, we
want to have the control hierarchy
complete before the load view state
stage arrives. For this reason, it is
best to create an event handler for
the Page class's Init event in your
code-behind class, and add your
dynamic controls there.
4) Unless you're doing something way outside of the box, ViewState is never modified client-side. "ViewState" is an HTML form field and is processed on the server side.
Here's a few images from Understanding ASP.NET View State by Scott Mitchell that may help you.
(source: microsoft.com)
(source: microsoft.com)
Bonus Reading Material: http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx
My impression used to be that the server encoded all the control
properties into the viewstate, and on the client side when the user
submitted the form, the viewstate field was decoded, modified,
encoded, and submitted to the server with modifications.
No, the point of the ViewState is simply to preserve the state of the page since the last "Save View State" page event, i.e. that event occurs shortly before the page is rendered to the client.
When the client makes selections to a dropdown box or changes text in a textbox the hidden ViewState property, which exists on the client page as a static HTML tag, is not dynamically changing / encoding those values, it remains the same as when the page was originally rendered.
So how is the new state of the page being preserved, i.e. how are user dropdown selections and text box values retained in ASP controls? Those dropdown selections and text box values are captured in Post Back data.
A server control can indicate that it is interested in examining the posted back data by implementing the IPostBackDataHandler interface. In this stage in the page life cycle, the Page class enumerates the posted back form fields, and searches for the corresponding server control. If it finds the control, it checks to see if the control implements the IPostBackDataHandler interface. If it does, it hands off the appropriate postback data to the server control by calling the control's LoadPostData() method. The server control would then update its state based on this postback data.
- Scott Mitchell
I'm looking for an easy way to explain this to someone. Apologies if it has been asked before.
It is a way to persist the page state between postbacks on the client. It represents a serialized string of the state of a page stored inside a hidden field and posted to the server at each request/postback (ASP.NET uses a single form and every time the user performs an action like clicking on the button this form is submitted to the server). Once the serialized state is submitted to the server it is capable of retrieving values that have been stored inside the view state.
Further reading: Understanding ASP.NET View State
By default, dynamic web pages do not keep their state. For example, you set a value for a variable in the page load event of asp.net page. You want to increment this variable when user clicks button. This is not possible because at every page postback, the variable is created and the page load event is executed therefore, the variable is set to the initial value. Then, you need a way to keep the value of variable even if page postback occurs. Viewstate can be used to solve this problem.
I have a simple user control containing two text boxes which I am adding to placeholder on Button Click event. I am storing the number(count) of clicks in View state and running a loop using count to create all previously added user control. I am also adding IDs to each User control (appending "UC" and count). I have also checked in view source the ids are same each time they are created. I have another button which basically does an post back. I have EnableViewState enabled ="true" in all controlls all the way up to Page Level.
My problem is that User Input does not persist on postback. please advice. Should this not be happening automatically for me?
Have a look at this:
http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx
I've encountered minor problems with it on a web farm, but for simple deployments its use is pretty straightforward. (Comes with source code, and the web farm glitch is a pretty simple fix.)
You need to create your dynamic controls in the Page_PreInit event rather than Page_Load or in a Click event handler. That way, they'll be there before ViewState, and then your posted values are applied.
I thinks what is happening is that you are creating your controls during the click event handler which happens AFTER ViewState and PostBack have been applied. This means your controls will be created empty each time.
I have a site that I am currently working on in ASP.NET 2.0 using the usual WebForm stuff and ASP.NET AJAX 1.0. Is it possible to bind an event to a dynamically created control after the Page.Load event?
I have a table <td> element that I am dynamically creating similarly to this code:
' Create Link Button
lnk.ID = String.Format("lnkDetails_{0}", dr("Id"))
lnk.Text = dr("Name").ToString()
lnk.CommandArgument = dr("Id").ToString()
AddHandler lnk.Click, AddressOf DetailsLink_Click
cName.Controls.Add(lnk)
This this code is looped over for each row in a database (and of course more cells are added to the table, including an ImageButton with an event. The events work flawlessly when I execute this code during events leading up to and including Page.Load. I need to be able to fill this table with current data, which is updated during a btnClick Event elsewhere on the page, which occurs after this Page_Load event, so I am populating with old data. If I change this code to Page.LoadComplete, events stop working.
This data is a summary display of various components of an application, things like somebody's name, which when updated on a 'detail' form, updates the database by partial postback (a requirement), then it needs to show the update in this 'summary' section after an update. Currently it takes 2 postbacks to actually see the change in the 'summary' section, so effectively the summary is 1 step behind the changes (clear as mud?)
What would be the best way for me to populate this table with current data (which is available during/after Page.LoadComplete), but still have an event fire when a link is clicked (the event causes an UpdatePanel to display the 'detail' form).
I also have jQuery at my disposal and the usual ASP.NET AJAX methods, also javascript is a requirement for the website, so I do not need to degrade for unsupported browsers.
This is my first ASP.NET web application and need some help figuring out the best way to make this happen (I'm well versed in PHP, Django and the usual ways to do web forms - things like having multiple forms on one page o_O).
Update:
There really isn't a good way to bind control events to controls after Page_Load. The overall architecture of the pages is there is one ASP.NET form encompassing the entire page, there is only 1 aspx page. I am using master pages (however it doesn't have any obvious implications to my issue).
The page is split into a left and right 'pane', the left is a summary of all the data (in an update panel), the right 'pane' has 6 'tabs' implemented each as their own user control, each with several form fields and an update button all in it's own UpdatePanel.
An update on any of these tabs only refreshes the summary panel (UpdatePanel.update()) and its own panel. The 'refreshing' and event binding of dynamic controls of the summary from the db happens during Page_Load and the Update Button event updates db data. (The control event happens after Page_Load). I want to avoid doing a double post to get the summary to update, any thoughts are helpful.
You need to postback the whole page after your data changes in the 'btnClick Event elsewhere on the page'. It sounds like you have an UpdatePanel and it sounds like this is catching the postback of your btnClick event handler. Put the btnClick outside the UpdatePanel or change its triggers so that your btnClick forces a postback/refresh of your data. Or, redesign your table so it's AJAXly-refreshed when you click on btnClick, it's hard to get you more details without knowing more about the structure of your page and controls.
Good luck!
You can bind to an event whenever you want. It's just a simple event after all. But not all places might be suitable because you have to take into account when the event fires. And in most cases this happens between Page_Load and Page_PreRender. That includes the click event on a LinkButton. In general, I would recommend to add your dynamically created controls in the Page_Init stage.
You have to add the controls before Page.Load in order to maintain ViewState between postbacks, so use the OnInit event handler for that.
But once they're added, you should be able to bind event handlers (such as OnClick) at any point during or after the Page.Load... for example in your grid's ItemDataBound (or something like) or in the Page.PreRender.