CreateChildControls before LoadViewState = Bug for DataGrid and Repeater

F

Ferret

I've found what seems to be a nasty bug in the DataGrid and Repeater
classes. If CreateChildControls gets called before LoadViewState,
ViewState fails to map and you end up with nothing on a Postback.
Please try the following test, and let me know if you can reproduce
this:

- Create a custom DataGrid or Repeater class that does nothing but
derive from one of the above and gives a place to put breakpoints in
overriden handlers
- Create a simple test case on a WebForm. I use template columns, but
BoundColumns might work as well.
- Create something in your DataGrid/Repeater that posts back, like a
LinkButton in a HeaderTemplate.
- Only DataBind if it's not a PostBack
- Put an EnsureChildControls at the beginning of OnInit in your custom
DataGrid/Repeater

When I click on the LinkButton, I get no output at all. Put
breakpoints in OnInit, LoadViewState, and CreateChildControls of your
custom class. If CreateChildControls gets called before LoadViewState,
nothing maps and there's no output. Now, if you take
EnsureChildControls out of OnInit, and your test is simple, you'll see
LoadViewState happen before CreateChildControls and everything will
work wonderfully.

Why is that? That's exactly opposite from everything I've learned so
far concerning server controls. Usually, the earlier you re-create all
your controls the better for mapping events, ViewState, etc. Why are
these framework control different? I can't avoid having my controls
created early in my big application because I usually put
EnsureChildControls in all my Properties, etc, like I thought was good
practice. Are DataGrids and Repeaters doomed to fail with these
practices?

I've considered finding a workaround. I even considered calling
LoadViewState at the beginning of CreateChildControls on a PostBack,
but I haven't tried it yet because I don't know if it would be safe to
do it even if it's possible. Any help or input on why this is
happening or any hacks or workarounds will be very welcome.
 
R

Robert Koritnik

ViewState is not populated until LoadViewState phase occures. Seems logical
doesn't it. Ok. So you've probably tried to create your control dynamically
in the OnInit phase.

To understand things better. For your events to fire its soon enough to
recreate your control in the PageLoad event. But your View state won't
persist.

How things work underneath. Let's just "simulate" the postback of the prerun
page:
0,9. Parse ASPX
1. OnInit
2. LoadViewState
3. ProcessPostbackData
4. Load
5 etc.

What it does is: It creates a control tree out of the ASPX, On init creates
server events and additional code, you may put there. After that the
__VIEWSTATE form field is loaded into controls to create the state that was
sent to the client. Afterthat ProcessPostbackData executes and updates
values to those that were posted back, so the runtime knows which Changed
events must fire. then the OnLoad fires and after that Cahnged events and
after those action events (clicks, command etc).

Think of this when designin your own custom controls.
 
F

Ferret

I don't understand your point. What does this have to do with what I
described? The problem is that both the Repeater and DataGrid fail to
populate from ViewState if CreateChildControls happens to occur before
LoadViewState. You didn't address that anywhere in your post.

This seems to be a bug in the DataGrid and Repeater. All the controls
I write repopulate fine from ViewState when CreateChildControls happens
early. In fact, everything I've read says that's best practice.

I appreciate your response, but I must have missed something.
 
F

Ferret

Microsoft finally admitted this is a bug and refunded the cost of my
support ticket. They did not, however tell me a better way to solve it,
so I'm still using my solution in my custom Repeater without any
problems so far. Here is my solution that you need in your custom
Repeater or DataGrid:

protected override void LoadViewState(object savedState)
{
base.LoadViewState (savedState);

// If our child controls have already been created, we need to call

// CreateControlHierarchy to give them a chance to bind from
// ViewState. This is the bug I've found in the Repeater and
DataGrid.
if (ChildControlsCreated)
CreateControlHierarchy(false); // builds templates and binds
from ViewState
}

The normal sequence of events is OnInit, LoadViewState, then OnLoad.
If CreateChildControls gets called in OnInit (very common and even
best-practice in most controls) on the Repeater or DataGrid during a
PostBack, it will NOT populate from ViewState.

Once again, this may fix a ton of "mysterious" issues with ASP.NET's
templated databound controls. The "DataGrid disappears" bug, some
"events not firing in DataGrid" bugs, etc. It is a rare occurence
though because CreateChildControls doesn't USUALLY get called on these
controls before the LoadViewState event. When making your own custom
controls, however, MS is very clear to point out that
CreateChildControls can get called "at any point in the control's
lifecyle", and you should definitely be able to handle it happening at
any point. I call mine in OnInit of pretty much all my custom controls
to prevent any timing-related bugs. MS just needs to read their own
docs.

Here is the MS response:

"Our developer has confirmed that it is a product issue. They are now
working on this problem, and it seems that there is no fix at this
time. I have forwarded your solution to them, and I will contact you if
there is any further update.

Our developer doesn't see any potential issues with your solutions. But
there may be issues under complex scenarios which is hard to predict
now. The best suggestion from them is to avoid calling
EnsureChildControls before the Viewstate is loaded."
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top