views:

345

answers:

1

I have code like the following in a UserControl:

Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
    If someCondition Then
        childControl.Enabled = false
    End If

    MyBase.Render(writer)
End Sub

Whenever someCondition is true and childControl.Enabled is set to false during the Render event, the ViewState for childControl is destroyed (i.e. if it is a TextBox, the text that the user has entered is lost).

Note that only the ViewState is lost... The control still renders with the correct property values the first time around. Only on PostBack, when properties are restored from ViewState are the values actually lost.

The timeline is as follows:

  • Page_Load (initial)
    Properties are set via code.
  • SaveViewState
  • Render
    Properties are modified.
  • Postback occurs.
  • LoadViewState
  • Page_Load
    Values of unaltered controls are still available, but controls which have had properties set during the Render method are blank.
  • SaveViewState

My understanding was that the ViewState became fixed during the call to Control.SaveViewState, which occurs prior to the call to Control.Render... But is there some nuance that I'm missing?

+2  A: 

Do controls that are disabled post empty values? Or post nothing at all? To be honest, I forget. But if they post empty values, then your viewstate is being overridden just like if you typed something new into the textbox and then posted the page.

Bryan
Except that the value displays correctly when the page is rendered. It is only after a postback that the missing ViewState is apparent. In other words, if childControl
AaronSieb
It's not surprising that it renders fine... But you are missing a step between LoadViewState and Page_Load... the step where controls are updated with the posted form values. Hence your problem.
Bryan
You know, I think you may be right. In order for this to be the case, a control would have to make the decision about whether it was going to read from ViewState or form submission prior to the Render method being called. I'll double-check the output and see what happens.
AaronSieb
I believe it does both every time. But processing postback data comes second and ViewState gets overwritten.http://msdn.microsoft.com/en-us/library/aa719775%28VS.71%29.aspx
Bryan
Incidentally, if you want to avoid this behavior it looks pretty easy to implement your own LoadPostData:http://msdn.microsoft.com/en-us/library/aa719775(VS.71).aspxYou could just check for "someCondition" and not update the control's value.
Bryan
Hm... Rendered output is the same except for the ViewState block regardless of whether I set Enabled during the Render method (which doesn't work) or before (which does). Looking into a ViewState decoder to get better analysis of the difference between the two. In either case the result looks like this: <input name="_ctl0:cpBodyContent:tbTest" type="text" value="This is a test" id="_ctl0_cpBodyContent_tbTest" disabled="disabled" />
AaronSieb
Will look into what extensibility hooks exist for LoadPostData. But I can't override it for the child control, and I'm reluctant to duplicate the entire implementation of UserControl.LoadPostData... Hopefully there are some child methods that I can override.
AaronSieb
Okay, I get it now. When the enabled value is set in Render, ViewState loads with the old value (enabled). Because the control is now enabled, it attempts to read its value during LoadPostData but gets an empty string because disabled controls don't contribute to POSTs. If the enabled property is set prior to render, the control reads that it is disabled from ViewState and knows to skip the LoadPostData step.
AaronSieb