Re: ViewState in a dynamic control

Discussion in 'ASP .Net' started by Ferret, Dec 3, 2004.

  1. Ferret

    Ferret Guest

    This has been confusing to me as well. I learned a ton about this
    while wrestling with a bug in the Repeater and DataGrid (see the post
    entitled "CreateChildControls before LoadViewState = Bug in DataGrid
    and Repeater"). Microsoft finally confirmed this as a bug in their
    controls.

    Basically, I learned that CreateControlHierarchy is the key here.
    CreateControlHierarchy(true) builds the control hierarchy and binds it
    to the DataSource for the control (if none is set at this time, you get
    no data or event wireups). CreateControlHierarchy(false) builds the
    control hierarchy and binds to a datasource created from ViewState.
    ViewState["_!ItemCount"] is used to determine if there is data in
    ViewState to bind to, and, I believe, is subsequently used to determine
    which version of CreateControlHierarchy to use.

    The problem with many templated databound controls is that many
    (including Microsoft's) aren't written to account for the fact that
    CreateChildControls might get called before LoadViewState occurs.
    ViewState["_!ItemCount"] isn't available until the ViewState is loaded,
    so if you're creating your child controls in OnInit (which is best
    practice and the solution to most timing issues), you don't know yet if
    you're supposed to bind to ViewState data or the DataSource. However,
    if you've already called CreateChildControls when LoadViewState rolls
    around, it won't even check to see if it should bind to ViewState data.
    Without the fix mentioned in my other post, most controls don't
    populate from ViewState at all on a PostBack when CreateChildControls
    gets called before LoadViewState. A typical scenario for this is
    clicking a column header to sort a DataGrid. If you have a custom
    DataGrid that calls CreateChildControls in OnInit, you'll need to alter
    the DataGrid for it to work.

    Needless to say, I found the MS documentation to be very poor in this
    area. I had to buy a custom control book to get enough information on
    CreateControlHierarchy and binding to DataSource or ViewState to figure
    this out.
     
    Ferret, Dec 3, 2004
    #1
    1. Advertising

  2. "Ferret" <> wrote in message
    news:...
    ....
    > The problem with many templated databound controls is that many
    > (including Microsoft's) aren't written to account for the fact that
    > CreateChildControls might get called before LoadViewState occurs.
    > ViewState["_!ItemCount"] isn't available until the ViewState is loaded,
    > so if you're creating your child controls in OnInit (which is best
    > practice and the solution to most timing issues), you don't know yet if
    > you're supposed to bind to ViewState data or the DataSource.


    Ferret,

    I haven't been in the habit of calling CreateChildControls in OnInit, and
    I've done alright. Where did you see that this is "best practice"?

    John Saunders
     
    John Saunders, Dec 3, 2004
    #2
    1. Advertising

  3. Ferret

    Ferret Guest

    Most of the answers to dynamic custom control problems are "you have to
    recreate the controls every time, and recreate them early". That's got
    to be the most common problem people encounter when events don't fire
    and output fails to show up. Usually people are using OnLoad to do
    logic on controls, and if they aren't created by then, there will be
    problems. The easiest way to avoid all those problems is to just make
    sure everything gets created in OnInit if not sooner (like
    EnsureChildControls being in a property that gets set in an ascx or
    something).

    I work with a lot of dynamically created custom controls, so maybe my
    view is skewed. The problem with dynamically created controls is the
    fact that their creation typically depends on some sort of decision
    factors. That's the realm I usually deal with. Any controls wanting
    to wire events on your control will need the control created first. If
    your control is contained in another control and needs to handle
    events, it becomes very important to get everything created early,
    especially the deeper your custom control hierarchy gets. Well, where
    else are you going to create them to ensure you don't have problems
    with other control interactions? I've encountered issues where even
    OnInit didn't seem early enough. Let's just say "early" has solved a
    ton of timing issues for me.

    So, to answer your question :), I would say most of it is personal
    experience with deeply-nested dynamic custom controls. There are,
    however a lot of MS articles talking about the importance of placing
    EnsureChildControls in all of your properties and making sure your
    controls are created before anyone can possibly interact with the
    control or its members. MS also makes it clear that
    CreateChildControls can happen at any point in a control's lifecycle,
    so not being able to handle it happening at a certain point is a
    potential bug. There are also a lot of good materials on its
    importance in the timing of event wireups.
     
    Ferret, Dec 10, 2004
    #3
  4. "Ferret" <> wrote in message
    news:...
    > Most of the answers to dynamic custom control problems are "you have to
    > recreate the controls every time, and recreate them early". That's got
    > to be the most common problem people encounter when events don't fire
    > and output fails to show up. Usually people are using OnLoad to do
    > logic on controls, and if they aren't created by then, there will be
    > problems. The easiest way to avoid all those problems is to just make
    > sure everything gets created in OnInit if not sooner


    We're mostly agreeing with each other - I wanted to make that clear to start
    out.

    Now that we're friends, we can have a nice, violent nitpicking discussion!

    I think the area where we don't quite agree is whether to force control
    creation in OnInit versus causing controls to be created "naturally" as soon
    as they're needed.

    > (like
    > EnsureChildControls being in a property that gets set in an ascx or
    > something).


    I agree with you on this case, but call it a case of "natural" child control
    creation. This was an instance where the existance of the child control was
    necessary to the proper execution of the property, so naturally,
    EnsureChildControls was called in the property accessor. Similarly, when a
    change to a property changes the set of "implied" child controls, then
    ChildControlsCreated should be set to false. It may be necessary to
    implement ISupportInitialize so that multiple property set operations aren't
    causing child controls to be created over and over again!

    > I work with a lot of dynamically created custom controls, so maybe my
    > view is skewed. The problem with dynamically created controls is the
    > fact that their creation typically depends on some sort of decision
    > factors. That's the realm I usually deal with.


    I find that things get a lot simpler if you can think of "dynamic child
    control creation" as "determination of the set of child controls based on
    property settings" followed by "creation of the set of child child controls
    when they are needed".

    > Any controls wanting
    > to wire events on your control will need the control created first. If
    > your control is contained in another control and needs to handle
    > events, it becomes very important to get everything created early,
    > especially the deeper your custom control hierarchy gets.


    Here, I think we may disagree a bit. I find the use of a sort of "Mediator
    Pattern" to be beneficial here. My control, "Composite", may expose an event
    called "CompositeEvent". Composite raises it when Composite feels it should
    be raised. Sometimes Composite raises this event when it handles an event
    from one of its child controls. This does not imply that the child control
    has to have been created before a calling page can wire itself to
    CompositeEvent.

    Consider the case where Composite has a child Button control and
    CompositeEvent is raised when the Button's Click event is raised. The
    calling page can wire CompositeEvent way back in OnInit - well before the
    child Button is even created. It will be created later, when it is needed to
    process its postback data. It will then rase its Click event to Composite,
    which will raise CompositeEvent, and the calling page will be happy.

    > Well, where
    > else are you going to create them to ensure you don't have problems
    > with other control interactions? I've encountered issues where even
    > OnInit didn't seem early enough. Let's just say "early" has solved a
    > ton of timing issues for me.


    "Early" is often overkill. "As early as necessary" is better (assuming you
    can figure out how early that is).

    John Saunders
     
    John Saunders, Dec 10, 2004
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Sparrow
    Replies:
    0
    Views:
    394
    John Sparrow
    Jul 1, 2003
  2. PABruceFan
    Replies:
    3
    Views:
    4,132
    John Saunders
    Jul 31, 2004
  3. Larry Bud
    Replies:
    1
    Views:
    356
    bruce barker
    Jan 10, 2007
  4. Josema
    Replies:
    2
    Views:
    364
  5. Josema
    Replies:
    0
    Views:
    214
    Josema
    May 9, 2005
Loading...

Share This Page