Using ASP.NET 4.0 WebForms.
I have a repeater with checkboxes in it. The repeater and checkboxes have viewstate enabled. There's a button which causes a callback postback. These elements reside in a callbackpanel (similar to MS's UpdatePanel but doesn't use viewstate). The repeater is bound to a datatable during initial load and repeater shows the checkboxes. Fine so far.
During the postback (a callback), I noticed that the repeater's items' count is 0 in the page_load. Therefore I can't get any checkbox values. I can see the key/checked value entries of the checkboxes in Request.Form collection.
I think I am missing something obvious but where in the life cycle can I read the repeater's items?
Or should I get them from Request.Form?
1) Try wiring up to LoadComplete. All child controls are loaded recursively, so sometimes not everything you expect to be there will be present during the Load event.
2) Make sure your repeater is initialized during or prior to Init event. If you have some code that runs to populate it, then this must be executed in Init. During the page's lifecycle, ASP.NET tries to take the posted values and apply them to the controls. If the controls are not created soon enough during the lifecycle, then they won't exist during that step to accept the posted values. This is one of the more frustrating things with dynamic pages in ASP.NET, as you have to ensure the page is reconstructed during the postback in init. So even when you see the data in the post, ASP.NET will ignore it if the controls aren't found in its collection of controls. Also, there is some magic that happens with control IDs that it uses to map the posted values into the controls. I don't remember the details of that though because it has been several weeks since I had to delve into the harry details.
Also, make sure you aren't doing something like using if(!IsPostBack) to initialize your repeater or other controls/data. Even if it's a postback, you still need the controls to exist so they can accept the posted values.
I have not used a callbackpanel though, so I am unsure of how this will muddy the waters.
I solved my problem by overriding the DataBind method on the control which contains the repeater. That prevents DataBinds on parent controls from trickling down and binding data to the repeater when it isn't ready for that. My problem was that a parent control/page performed a DataBind which trickled down to the sub-controls, including the repepater, causing it to get cleared. So you don't have to do a DataBind directly on the repeater on every postback like #AaronLS suggests:
Also, make sure you aren't doing something like using if(!IsPostBack)
to initialize your repeater or other controls/data. Even if it's a
postback, you still need the controls to exist so they can accept the
posted values.
All my RepeaterItems were stay present through postbacks even though I only databind once.
In my case, performing a DataBind on the repeater for every postback caused the form values to be reset.
Related
I have a FormView in an ASP.NET UserControl. The EditItemTemplate contains some controls, and I'd like to run some code server-side whenever they are created, to set some values based on some conditions.
It appears that the Control.Load and PreRender events are unsuitable for this, since the control can sometimes be rendered without any child controls (not sure why that happens). Specifically, if I look at FormView.ChildControlsCreated in the debugger, I always see True, but when I try to FindControl by name, sometimes it's there and sometimes it isn't.
When should I execute my code that requires access to the inner controls?
This happens because the FormViewMode is sometimes different. There is no template for ReadOnlyMode, so whenever the form is in that mode, FindControl doesn't find anything.
I have some questions about how and when data sources are bound in the page lifecycle, and I can't seem to find the answers anywhere.
I have a gridview which is bound to a data source at design time. One of the parameters for the DS is the selected value of a dropdown list. These dropdown lists are also databound to retreive their options, and the dropdowns have their auto-postback property set true. Now some things are confusing me about this.
Most of the time changing the value of the dropdown will reload the gridview with the new parameter, and it's not necessary to manually call databind() on the gridview in order to do so. However there are situations where the gridview is not rebound, and I'm not sure what these conditions are. When will a data-source be rebound automatically upon parameter change, and when do you need to call databind manually from code?
Does calling databind from codebehind prevent the automatic databind event from firing, or will they both fire, resulting in a wasteful extra query of the data source?
If the former, is there a way to stop the extra databind from occurring without having to move everything into code behind and lose the convenience of setting up data sources for the controls in the design view?
Are the answers to these questions documented on any official sources? (MSDN, etc)
I can't be sure without looking at you code, but you probably want to read about ViewState.
Once the control has been loaded, the data stays in the viewstate. You generally want to do the DataBinding on (!IsPostBack) event so that on postbacks you do not need to rebind the data from the DB.
I am using entity framework 4.0 to bind a database object to a DetailsView on an ascx control. Within the DetailsView, I have a number of asp:panels that I'd like to show/hide depending on what's happening in that person's visit.
So, the first time through the page I'm setting panelA.Visible=false in the FormView_OnLoad event, and all is well - that panel is not output in the HTML. It listens to what I'm asking here.
Once I click submit and postback, I am again checking what's going on and setting panelA.Visibe=false in both FormView_OnLoad and EntityData_OnUpdating. But this time, when the page comes up panelA is showing.
I find that I can only hide that panel after postback by setting visible=false in DetailsView_PreRender, or by binding visibility to a public variable.
I'm thinking perhaps in the life cycle the DetailsView is binding again way toward the end, and throws away my visibility settings, even though they're not bound. So to show/hide panels within the DetailsView on postback, will I always have to set visibility on DetailsView_PreRender or after?
Am I on the right track here, or is something else resetting me at the last second?
Why can I set visibility the first time through the page but not postback?
You should always make final modification of your page structure after postback processing - that is the reason why PreRender event exists. Other possible event in your scenario can be handling DataBound event but better and more clear way is PreRender.
I've been getting this exception in my code and wondered if anyone could help me out.
I have a Repeater Control bound to an ObjectDataSource, and the itemtemplate for the repeater contains a User Control (ASCX). This user control in turn contains several other controls, mainly a GridView that is associated with an ObjectDataSource.
On initial use of the controls in this setup, everything works great - data displays properly. However, when I change a filter option (dropdowns outside of the repeater), and then rebind the Repeater, I get the exception:
The ObjectDataSource control 'expDataSource' does not have a naming container. Ensure that the control is added to the page before calling DataBind."
at System.Web.UI.WebControls.DataBoundControlHelper.FindControl(Control control, String controlID)
...
...
at System.Web.UI.WebControls.ObjectDataSource.LoadCompleteEventHandler(Object sender, EventArgs e)
I'm not sure what the problem is - I've read in a few places that moving the datasource outside of the ASCX control might help - this does nothing. The objectdatasource appears to be properly structured, and as I said, it works the first time (only).
I noticed in the stack trace for the exception that this is occurring when ASP.NET is calling FindControl() after LoadComplete() occurs. If I step through my code, it appears as though all my code is finished executing before this happens, so it's all "system" code.
Why would ASP.NET not be able to find this datasource control in the LoadComplete Handler?
Thanks!
Other Notes:
This error occurs every other time. So the first time the data loads properly, then on second refresh fails with this error. Clicking "Load" again, it works (on the third time).
On the times that it fails, it looks like "Page_Load" is being called twice in the ASCX control. So the patterns are:
Working Pattern:
Page_Load on Parent Page
Page_Load on ASCX
Data Loads fine
Failing Pattern:
Page_Load on Parent Page
Page_Load on ASCX
Page_Load on ASCX
Exception
This is all happening from a call to "Repeater.DataBind()", but it behaves differently depending on if it has already been bound or not (evidently).
More Notes:
Real strange behavior. I removed the list of SelectParameters from the bottom of the ObjectDataSource, and all of a sudden, the page does not reject the ObjectDataSource as not having a NamingContainer. Of course, without these parameters, Databinding won't actually work...I can add them in the code, but why would it matter?
Found a strange solution, that I'll post and we can discuss to maybe figure out why this fixed it.
On my page, I had the following structure (paraphrasing the tags somewhat):
Page
DropDownFilter
Repeater
UserControl X
ObjectDataSource
ControlParameters Referencing DropDownFilter
End ObjectDataSource
End UserControl X
End Repeater
End Page
So as you can see, within the Repeater ItemTemplate was the user control, which in turn had the "guilty" ObjectDataSource with ControlParameters. These control parameters had the name of the DropDownList filter on the parent page referenced (so basically, if this control was added to any other page, it would of course fail if it couldn't find a control with the proper name).
So when I went through and changed all the ControlParameters to Parameters (removed the reference to that DropDownList control), now I no longer get the error.
All I can assume is that the fact that this datasource referenced a control on the parent page meant that it was having trouble getting added back to the page's control set on a DataBind(). You would have thought it would fail the first time if it was going to fail at all, so that's still a mystery.
Any thoughts?
This is an exceptional error in ASP.NET DataControls. I had similar problem and lost few months behind this eccentric error, but finally got the solution. The reason is; To display items in ItemTemplate, we should use a server control in the LayoutTemplate to act as the placeholder for the ItemTemplate. For example, we could use a Table/Div control with an ID Property in Layout Template. At run time, this placeholder control will be replaced with the contents of the ItemTemplate and "naming container error" will be disappeared.
Finally, if you are having an objectDataSource in ItemTemplate, make sure that you added somthing(like table/Div) with "Id" property in Layout Template.
Thanks,
Sunil.
Ray hit the nail on the head. You are definitely missing an "if(!IsPostBack)" somewhere. How are you adding the user control to the repeater? Is it dynamic? You say it's in the ItemTemplate, so probably not... But multiple calls to Page_Load imply multiple copies of the control.
Use both DataBind. Example:
SqlDataSource1.DataBind();
ListView1.DataBind();
When a page is posted back, which statement runs after page_load is done executing? Without knowing what controls are in the page. This is in VS 2008 debugger.
EDIT:
The question is about knowing which event and for which control comes next.
ASP.NET Page Lifecycle
PreInit
Init
InitComplete
PreLoad
Load
Control Events (e.g. ButtonClick)
LoadComplete
PreRender
SaveStateComplete
Render
Unload
The "next statement" is indeterminate. To put it another way, in the sense of "separation of concerns", it's none of your concern. It's the concern of ASP.NET, but not of individual controls on a page, nor of individual developers debugging a page.
I recommend that you determine what question you really needed answered, and what problem you really needed solved.
Here's an example of "why not": Consider the DataBinding event, which is raised when the Control.DataBind method is called, often from inside of Page_Load. Consider a page that contains a DataGrid control. When Control.DataBind is called, the DataBinding event is raised for the control, and Control.DataBind is then called on each control in Control.Controls, eventually causing DataBinding to be raised for those controls. When it gets to the DataGrid, the control will populate its Controls collection with one row for each row in the input data.
Each of the added controls will need to "catch up". They will go through the PreInit, Init, Load, etc. phases - everything up to DataBind.
There's no way to know ahead of time which controls will be added, so you certainly can't determine which events will be fired, and in which order. In fact, some of the control events will fire or not depending on the previous state of the controls. A SelectedIndexChanged event on a dropdown control in a template column of one of the rows may fire if the dropdown index has changed from the last postback, but not if it has stayed the same!