Can someone explain exactly how/when an ObjectDataSource fires? I have an ASP.NET page, with a GridView, which is referencing an ODS. I put a breakpoint in the method the ODS is using, and noticed it was firing twice.
I looked into the code and the answer seemed obvious at first. I had
Page_Load()
{
if(!Page.IsPostBack)
{
MethodA();
MethodB();
}
}
where MethodA and MethodB were both eventually calling gv.DataBind(). This made sense because I assume that each call to GridView.DataBind() would result in asking the ODS for data, and therefore running my data access method.
The weird thing is that when comment out the call to MethodA, it still fires twice. Checking the call stack shows the method being run first as a result of MethodB, and then again, with no trail except [External Code]. This mystery load does not happen when I let MethodA and MethodB both execute.
Any idea what's going on here? Any idea what other code I might have that is asking the ODS for data? I'm starting to think all these 'no code' data controls are more obfuscation and BS than they're worth.
I've experienced this problem when we were hiding/showing gridview column dynamically in code.
Here is a page that talks about some issues that might cause multiple Selects
http://forums.asp.net/t/1161164.aspx
Multiple calls to a gridview's databind method can occur implicitly if you're changing the visibility, i.e., showing and/or hiding, the columns of a gridview tied to an object data source.
In this scenario, try encapsulating the show/hide gridview column code in the Page_LoadComplete event handler.
The Page_LoadComplete event handler is in a prime position in the page lifecycle to prevent multiple databind calls and still be effective as it is invoked after control change events (e.g., button click, drop down selected index changed, etc.) yet before the gridview databinding events.
"when comment out the call to MethodA, it still fires twice". So it will likely be Page_Load called twice. Probably you have AutoEventWireup="true" and also registering event in code http://www.aspdeveloper.net/tiki-index.php?page=ASPFaqEventsDoubleFire
If you set the datasource of the gridview with something like
gv.DataSourceID=dsObjDataSource;
then the grid view calls gv.DataBind() on its own.
I had the same problem - the problem was that I was hiding/showing a column after, or during, databinding. Moving the hide/show code before the databinding stopped the binding from happening twice, which I suspect is the same effect as moving it to the Page_Load. In my case the databind was happening in response to a dropdown listbox change - doing the column add/remove before the DataBind() call fixed the twofer problem for me.
I was getting the same result with DataBinding occuring twice using asp:DataList and asp:ObjectDataSource.
It turned out to be because I was using a UserControl in the select parameters:
<asp:ControlParameter Name="GroupID" Type="Int32" DefaultValue="-1"
ControlID="UserControl1" PropertyName="SelectedGroupID" />
I am getting weary of UserControls. I can see how they might be productivity enhancement for 5th graders but they are a complete waste of time at a higher level.
Related
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.
I have an ASP.NET page using the AJAX library. There is a dropdownlist inside an UpdatePanel, which on index changing is supposed to update a different UpdatePanel to modify a grid control.
But after the page first comes up, and you adjust the ddl, the entire page postbacks, followed by a (correct) partial postback. After this one time, every other usage of the ddl performs correctly, trigger partial postbacks.
Both the panel and the ddl are being added from code. The UP is Conditional updates and ChildrenAsTriggers = true. The dropdownlist is AutoPostBack true and has an event set up on SelectedIndexChanged.
So what is going on? I've tried adjusting every setting I can think of and still the page completely refreshes once, then works fine after that.
I believe I've solved my current woes in regards to this problem, though I'm left feeling a bit dumb by the outcome. When programmatically adding the dropdownlist, I didn't give it an ID, assuming ASP.NET would just assign it some sequential name-container mangled ID anyway. It seems this was the cause. I'm assuming that the initial postback was due to ASP.NET trying to deal with the lack of a proper ID, assigning one, and then using that afterwards for the partial postbacks.
Or maybe it's something totally different at root, but the simple fix was: add an ID to the control.
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!
To Clarify to all this problem absolutely does not stem from rebinding of the controls and the value does not remain the initial value after binding.
I have a DropDownList on an aspx page which is being used in multiple projects.
Along the life cycle of the page the SelectedValue is changed prior to the handling of the SelectedIndexChanged event.
In one project when the code reaches the event handler the SelectedValue is back to what was posted from the client, while in the other the new SelectedValue is present.
Viewstate is on in both cases, the control is not being rebound and follows the exact same flow from all that I can gather.
The control is not being initialized again, I checked this thoroughly and does not retain the initial value but rather the value set in the code.
I actually need the posted value at the point of the event handler like is happening in the first project but do not understand why it would be changing back to the posted value and how to replicate this behavior in the second project.
I will be happy to clarify further if any of this is unclear.
Maybe some initialization is performed twice in the on_load event because you dont check the page is posted back using IsPostBack in a test ?
It exactly happens to one of my colleague ten minutes ago :-)
Many people wrongly believe that DropDownLists must have ViewState on to be able retain selected value. I almost never have EnableViewState set to true on DropDownLists because they work fine in a form with the posted values. (And setting it to true on a DataBinding control will cause a long viewstate)
The posted value (selected item in the dropdown) is loaded from the post-parameters after OnInit in the page so if you bind the data to the dropdown in OnInit it will work fine.
If you bind in OnLoad, the selected Value will be overridden.
Perhaps you are databinding in the wrong event so that the selected value gets overridden by a DataBind-call on the dropdown?
I usually see this behavior when I've forgotten to check IsPostback somewhere. The page will load all of the original data before going to the SelectedIndexChanged event handler.