This is going to be long and detailed.
Let's start with this markup. Almost identical to yours, with one additional button and a label. I'll explain why we need them later.
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server" EnableViewState="False" ViewStateMode="Disabled" Text="Before click"></asp:Label>
<asp:TextBox ID="TextBox1" runat="server" EnableViewState="False"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_OnClick"/>
<asp:Label ID="Label2" runat="server" Text="Blah" />
<asp:Button ID="Button2" runat="server" Text="Button" OnClick="Button2_OnClick"/>
</div>
</form>
And we'll use this code behind. Again, I'll explain the purpose of the second handler later on:
protected void Button1_OnClick(object sender, EventArgs e)
{
Label1.Text = "Changed";
}
protected void Button2_OnClick(object sender, EventArgs e)
{
Label2.Text = Label1.Text;
}
Let's see what happens when we initially load the page. First ASP.NET reads all the markup, and then goes through the page life cycle with all the events. In markup parsing stage Label1
gets assigned text Before click
, and it is never changed later during initial load. So later during rendering phase this is what is getting rendered into HTML and sent to browser. Thus Before click
is displayed on the screen. Nice and easy.
Now we click Button1
. Postback occurs, which is a term that describes a request sent to the same page by one of its controls after it was initially loaded. Again, everything starts with ASP.NET parsing the markup, and again Label1
gets assigned text Before click
. But then page life cycle events happen, including control event handlers. And in the handler for Button1
the text of Label1
is changed to Changed
. Now here is the important thing to note: if ViewState for the Label1
was enabled, this new value would be stored in there, and so called tracking would be enabled for property Label1.Text
. But ViewState is disabled, and so the new value is not stored anywhere except Label1
. Next comes the rendering page stage, and since Label1.Text
still holds the value Changed
this is what is rendered into HTML and sent to the browser to display. Note however that this new value is not sent inside the ViewState
field. As you can see, whether ViewState is enabled or not plays no role in what is displayed after this postback.
Now we'll click Button2
, which would trigger another postback. Again, ASP.NET parses the markup, again Label1
gets text Before click
. Then comes ViewState loading part. If ViewState for Label1.Text
was enabled, it would load changed value into this property. But ViewState is disabled, and so the value stays the same. Thus, when we reach Button2
click handler, the value of Label1.Text
is still Before click
, which is assigned to Label2.Text
. But Label2
has ViewState enabled, and so this new value for its text is stored in ViewState and sent to the client (ViewState is implemented as a hidden field on the client side). When everything gets to the browser, we can see Label1
and Label2
both displaying Before click
.
And to nail it down we'll do a third postback, now clicking Button1
again. Just as during the first postback, Label1
ends up with Changed
text. But what about Label2
? Well, this one has ViewState enabled, so during initial markup parsing ASP.NET assigns it the value Blah
, and during ViewState loading it replaces this value with Before click
. Nothing else affects this value during the page life cycle (we did not click Button2 this time), and so we end up seeing Changed
and Before click
in the browser.
Hopefully it makes it clear what the ViewState is for and what disabling it does. If you want to dive even deeper into how ViewState works, I would greatly recommend this article: TRULY Understanding ViewState.