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
Related
This subject seems to be be beaten to death and yet I still can't find an answer.
I am trying to allow users to click a button to add a usercontrol to a page. Hypothetically, they can do this as many times as they want. I know I need to recreate these controls on Postback, and am trying to do this in Page Init so that viewstate can give them back their values in page load.
My problem is I have no idea how to keep a running counter that I can use in Init to recreate the proper number of controls the user has put on the page. Viewstate is not available in Init so I can't just use a hidden field where I could increment or decrement the value. I also cannot use Session variables. I am not allowed to use them in this particular project.
As an FYI, I'm adding and deleting these usercontrols successfully right now when I do it on Page Load. But, the fields within the usercontrol do not retain their values consistently between postbacks.
You can always keep this count in the client, and add it to the URL for instance.
I'm trying to build a very specific search page for a project and I'm having lot of trouble dealing with multiple postbacks invoked by dynamically-generated controls on a single page.
The page has to work like this:
There is a single checkbox, "Detailed search", that causes a postback on checking/unchecking.
When detailed search is not active, a simple grid with contents and buttons is displayed. Nothing special.
When detailed search is active, N checkboxes must be generated from some dynamic data, that represent the sections where you want the search to happen. Below the checkboxes, an AJAX-enabled tab control will appear, initially with no tab pages.
When checking one of the section checkboxes, a postback will occur. After the postback, data will be searched in the section selected by the user, then a new tab page containing a grid view of results and the name of the section will be added to the tab control. If the checkbox is unchecked, the tab page will disappear from the control, again, after a postback.
Now, the issue is that pretty much everything has to be generated dynamically, and that pretty much everything is connected to something else.
First issue: dealing with the "Detailed search" checkbox. Sounds easy, doesn't it? My initial idea was to set Page.Viewstate["DetailedSearchEnabled"] to true or false during the check/uncheck event handler, then create controls dynamically checking the value of DetailedSearchEnabled during Page_Load.
Nope. The postback event-handling happens between Page_Load and Page_LoadComplete. It would take an additional refresh for things to work as intended.
<< Then I'll just generate the controls on Page_LoadComplete! >>
Nope. Those controls need event handling as well, and if they're generated after Page_Load they will not be wired up correctly.
A possible solution would be generating everything in advance, on Page_Load, and only hiding/showing controls on Page_LoadComplete. But that is inefficient, and one important point of this search page is that only the minimum amount of controls should be generated.
The difficulty of this task seems to come from the way event wiring and the page life cycle work.
Surely there must be a better way of approaching this problem.
First issue: dealing with the "Detailed search" check box.
The correct approach (if you want to use page post-backs) is as follows:
In the CheckChanged event handler, save the value of the Checked property to ViewState["DetailedSearchEnabled"]. If the value is true, add the dynamic check boxes to the page. If the value is false, find and remove them.
Override LoadViewState. After calling base.LoadViewState, re-create the dynamic check boxes and wire up their events if ViewState["DetailedSearchEnabled"] is true. Note that neither Page_Load nor Page_LoadComplete is the appropriate place to do this.
Yes, you should create the dynamic check boxes at two points in the page life cycle. I recommend a helper method.
In general, your event handlers should add or remove just the dynamic controls (if any) affected by those particular events, but LoadViewState should re-create all dynamic controls that existed from the previous page request. You must store enough information in view state for LoadViewState to do so.
My answer to this other question demonstrates how to add and remove dynamic controls. You may want to use it as a reference.
Sounds to me like you should be using a CheckBoxList control to handle your dynamic checkboxes. You can add an remove items to the CheckBoxList during your post back and not have to worry about dynamically adding/removing actual controls/events to the form.
Here is a link to the msdn:
https://msdn.microsoft.com/en-us/library/14atsyf5(v=vs.85).aspx
Here is some sample code:
Protected void Button1_Click (object sender, System.EventArgs e)
{
CheckBoxList.Items.Add(new ListItem("TextValue1", "Value1"));
CheckBoxList.Items.Add(new ListItem("TextValue2", "Value2"));
}
If all else fails, you could still fall back on the quick-and-dirty old-fashioned ASP way.
Use Response.Write or <%...%> to generate your dynamic controls as plain old HTML (simple form fields, e.g. <input type="checkbox" name="foo" value="1" />).
Make sure you have a form field for every piece of information you may need after the postback(s). If necessary, use hidden form fields to 're-post' values across subsequent postbacks.
After postback, retrieve the values of the controls with the Request object.
Use those values to adjust the generation of controls as you see fit.
You should be able to do all of this in Page_Load. The advantage is total freedom. The disadvantage is total freedom to make a big mess of your aspx. So you may want to migrate all this dirty code out of your aspx, and into a custom-made control, which you can then add to your aspx.
When generating your own HTML, be careful not to introduce XSS vulnerabilities. Use HtmlEncode where necessary.
As you suggested yourself, there is a better way to tackle it.
If I was in the same situation, I would create web methods for interacting with the page, and use client side to do the UI. I'm currently working mostly with angular JS, although it does come with a learning curve. You could use ng-hide/ng-show to bind to the checkbox event to display the detailed search. When the n number of checkboxes needs to be displayed, you can then just fill them in with ng-repeat, for each of the items you need to display, after a check/uncheck you can dynamically populate new controls etc. through web method calls if extra data is needed.
Pure ASP postbacks are quite clunky from my experience, and not really suited for building a maintainable dynamic UI.
Instead of making so many postbacks, it would be better to use jquery and ajax calls to load the controls as needed and then attach events to it or you can even use UpdatePnael for that. Help Links:
https://www.simple-talk.com/dotnet/asp.net/ajax-basics-with-jquery-in-asp.net/
http://encosia.com/using-jquery-to-directly-call-aspnet-ajax-page-methods/
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.
i have a form that is generated dynamically.
the plan is to generate it, the user to enter data, and then to save all that lot away.
although a slight variation to this is if the form has previous data associated with it, and then it loads in all pre-populated. - the user may then change any previous selections.
and that is the rub really, i know if i call generateform regardless of postback the viewstate should take over and remember what the settings weer.. but as the generateform method as mentioned above populates the form if the form has previously been saved. which will win, the viewstate or the generateform method for the field populations.. ?
thanks
nat
If you dynamically generate any form controls that post data or cause a postback, you need to recreate them again on postback in order for them to be bound to their data, or their events, after the postback. Conceptually, this makes sense. If you don't have a control in your form after the postback, how could you look at its contents?
There are several ways you could approach this problem.
1) Call GenerateForm() no matter what. Since you said it pre-populates some of the data, you would need to change it so it can be called without doing that. ASP.NET will populate the controls with the data posted automatically on postback, which is what you want.
2) Keep a list of all your dynamically generated controls in a ViewState variable, so you can re-generate them upon postback. For most situations involving dynamically-created controls that aren't very simple (e.g., you may not know in advance exactly what controls are generated), this is the best solution. And often you will want to be able to access the data after a postback, but maybe you really don't want to recreate the whole form because you aren't using it any more.
As long as you recreate a control of the same type and ID on or before Page_Load(), it will be bound to the posted data. It does not need to be in exactly the same place on your form. And it does not need to be used or displayed, either - you can destroy it before the form is rendered, e.g., in Page_PreRender()
3) If you have no interest in any of this, you can always use Request.Form to look directly at the posted data, though this can also be tricky because the names will likely not match your form control IDs exactly. ASP.NET generates unique client-side IDs that depend on the container, and this is what you'll find in Request.Form. If you don't regenerate a control, you may not be able to easily determine the ID that you are looking for. Generally, you should not do this, but it's a way to look at the posted data and sometimes you need it.
I am writing a survey generating system in asp.net. i asked an ealier question about the best way to create controls that can be passed about as variables. This was problematic with user controls so i was advised to use custom controls and a quick way to do this was to inherit from the panel control and just add a bunch of standard controls the the controls collection by overriding the CreateChildControls method. This way i could create my "survey" controls,which are basically Questions in the survey. THe question controls are then dynamically added to the page. This all works well but know i have come to the point that i want to try and retrieve the values from these controls and i seem to be lost in a nether world of of viewstates and page lifecycles. I can ensure that the dynamically added text boxes have a known ID, however even if i add the parent control in the page init handler the CreateChildControls method does not run until after until after the viewstate is loaded. I cannot work out how to retreive the values from these text boxes.
You can call the EnsureChildControls method on the init handler of your control to ensure CreateChildControls is called before the ViewState is loaded.
You certainly seem to be doing this the hard way. TextBox values are not saved in the Viewstate, they are posted in the request.
Why aren't you using a UserControl here? So you can "pass" it somewhere? what exactly are you trying to do?