I recently responded to a newsgroup post on microsoft.public.dotnet.framework.aspnet.webcontrols that I thought warranted a follow-up comment here. The posters question was:
I have a Panel control containing a few TextBox controls. The Panel is originally enabled, I enter data into the TextBox controls. When I submit, the Panel is disabled during the PostBack and the TextBox controls render greyed-out, and I can see the values in the TextBox controls....this is what I expected.
I submit again, the Panel is enabled during the PostBack. All of the TextBox controls within the Panel are now enabled, however, the values are gone. This doesn't happen with a TextBox control outside of the Panel that is also enabled/disabled.
The post then contained a sample ASP.NET Web page that illustrated the problem. Namely, it had a Panel Web control with a TextBox Web control inside of it, along with a CheckBox and a Button outside of the Panel. When the page was posted back, if the CheckBox was checked the Panel's Enabled property was set to False; if the CheckBox was unchcekd, the Enabled property was set to True.
I started by testing the poster's source code in Mozilla Firefox, my default browser. When the Panel's Enabled property was set to False, the TextBox was still editable and not grayed out, nor did I lose the TextBox value when posting back after it was disabled. Doing a view source illustrated why: the Panel renders as a <table> for downlevel browsers. Setting the Enabled property to False created a table with the attribute disabled=”disabled”.
Switching to IE6, I reran the test and was able to replicate the poster's problem. IE6 renders a Panel as a <div>. When the Panel's Enabled property was set to False, the following HTML markup was generated:
<div id="panelID" disabled="disabled">
<input type="text" name="textboxID" id="textboxID" value="valueEnteredOnLastPostback" />
Note that the disabled attribute only applies to the <div>, and not the <input>. (This was the case in Firefox, too, except instead of a <div> it was a <table>.) Interestingly, with this HTML markup, IE displays the TextBoxes as grayed out - however, I could edit them! What's really interesting, though, is that when the form is submitted, IE doesn't send back the values of the TextBoxes in the HTTP POST header. I guess it hits the <div>, sees that it is disabled, and then doesn't bother processing the <div>'s inner children. (Firefox always posts back the TextBox value, regardless of the value of the enclosing <table>'s disabled attribute.) Since the TextBox value is not posted back when the Panel is disabled, the TextBox loses its Text property value, resulting in an empty TextBox on postback. The solution to this problem is to explicitly set the TextBox's Enabled property to False - not just the Panel's.
The reason the problem exists is because when a visitor enters a value into a TextBox, and posts back the form, that value is not persisted into the TextBox's view state. Yes, the value is saved to the TextBox's ViewState property, but the view state for the TextBox is only saved if the TextBox's TrackViewState property is set to True. I'm going to gloss over the sticky internal details, but realize that the TextBox does not record its Text property value in its view state if the TextBox is a Password TextBox or if there is not an event handler wired up to the TextBox's TextChanged event. If the Text property is the only property set after the Initialization stage, then the TextBox won't record any view state information. The means by which TextBox's persist their Text values across postback is by having the TextBox value continually posted back in the HTTP POST headers... but when using a disabled <div>, the TextBox value is not posted back.
An astute reader might then counter, “Well, if what you say is true, then why does explicitly setting the TextBox's Enabled property to False make everything work? After all, when the Panel is disabled, the TextBox's value is not being posted back, right?” Right you are, but when you set the Enabled property to False explicitly, that has the side-effect of setting the TextBox's TrackViewState property to True, so both the TextBox's Enabled and Text properties will be persisted to view state, and hence be used to repopulate the TextBox.
A final question readers might have is, “How in the world did you find out all this stuff?” Through the book Developing Microsoft ASP.NET Server Controls; using Reflector to look at the decompiled source code of the System.Web.UI.Control, System.Web.UI.Page, System.Web.UI.WebControls.TextBox, and System.Web.UI.WebControls.WebControl; and using a view state parser (specifically, I used one I will be presenting in an upcoming article on ASP.NET View State on MSDN, but you could use Paul Wilson's View State Parser, or Fritz Onion's ViewState Decoder).