TRULY Understanding ViewState

ViewState is a very misunderstood animal. I would like to help put an end to the madness by attempting to explain exactly how the ViewState mechanism works, from beginning to end, and from many different use cases, such as declared controls vs. dynamic controls.

There are a lot of great articles out there that try to dispel the myths about ViewState. You might say this is like beating a dead horse (where ViewState is the horse, and the internet is the assailant). But this horse isn't dead, let me tell you. No, he's very much alive and he's stampeding through your living room. We need to beat him down once again. Don't worry, no horses were harmed during the authoring of this article.

It's not that there's no good information out there about ViewState, it's just all of them seem to be lacking something, and that is contributing to the community's overall confusion about ViewState. For example, one of the key features that is important to understand about ViewState is how it tracks dirtiness. Yet, here is a very good, in-depth article on ViewState that doesn't even mention it! Then there's this W3Schools article on ViewState that seems to indicate that posted form values are maintained via ViewState, but that's not true. (Don't believe me? Disable ViewState on that textbox in their example and run it again). And it's the #1 Google Search Result for "ASP.NET ViewState". Here is ASP.NET Documentation on MSDN that describes how Controls maintain state across postbacks. The documentation isn't wrong per say, but it makes a statement that isn't entirely correct:

"If a control uses ViewState for property data instead of a private field, that property automatically will be persisted across round trips to the client."

That seems to imply that anything you shove into the ViewState StateBag will be round-tripped in the client's browser. NOT TRUE! So it's really no wonder there is so much confusion on ViewState. There is no where I've found on the internet that has a 100% complete and accurate explanation of how it works! The best article I have ever found is this one by Scott Mitchell. That one should be required reading. However, it does not explain the relationship of controls and their child controls when it comes to initialization and ViewState Tracking, and it is this point alone that causes a bulk of the mishandlings of ViewState, at least in the experiences I've had.

So the point of this article will be to first give a complete understanding of how ViewState basically functions, from beginning to end, hopefully filling in the holes that many other articles have. After a complete explanation of the entire ViewState process, I will go into some examples of how developers typically misuse ViewState, usually without even realizing it, and how to fix it. I should also preface this with the fact that I wrote this article with ASP.NET 1.x in mind. However, there are very few differences in the ViewState mechanism in ASP.NET 2.0. For one, ControlState is a new type of ViewState in ASP.NET 2.0, but it treated exactly like ViewState, so we can safely ignore it for the purposes of this article.

First let me explain why I think understanding ViewState to it's core is so important:

    MISUNDERSTANDING OF VIEWSTATE WILL LEAD TO...
  1. Leaking sensitive data
  2. ViewState Attacks - aka the Jedi Mind Trick -- *waves hand* that plasma tv is for sale for $1.00
  3. Poor performance - even to the point of NO PERFORMANCE
  4. Poor scalability - how many users can you handle if each is posting 50k of data every request?
  5. Overall poor design
  6. Headache, nausea, dizziness, and irreversible frilling of the eyebrows.
If you develop an ASP.NET Application and you don't take ViewState seriously, this could happen to you:
ViewState Madness!!! Drop your red bull and surrender your cpu cycles. You will be frustrated. Performance is futile!
The ViewState form field. ViewState will add your web app's distinctiveness to it's own. Performance is futile.
I could go on but that is the gist of it. Now lets move on by starting back from the beginning:
    WHAT DOES VIEWSTATE DO?
    This is a list of ViewState's main jobs. Each of these jobs serves a very distinct purpose. Next we'll learn exactly how it fulfills those jobs.
  1. Stores values per control by key name, like a Hashtable
  2. Tracks changes to a ViewState value's initial state
  3. Serializes and Deserializes saved data into a hidden form field on the client
  4. Automatically restores ViewState data on postbacks
Even more important than understanding what it does, is understanding what it does NOT do:
    WHAT DOESN'T VIEWSTATE DO?
  1. Automatically retain state of class variables (private, protected, or public)
  2. Remember any state information across page loads (only postbacks) (that is unless you customize how the data is persisted)
  3. Remove the need to repopulate data on every request
  4. ViewState is not responsible for the population of values that are posted such as by TextBox controls (although it does play an important role)
  5. Make you coffee
While ViewState does have one overall purpose in the ASP.NET Framework, it's four main roles in the page lifecycle are quite distinct from each other. Logically, we can separate them and try to understand them individually. It is often the mishmash of information on ViewState that confuses people. Hopefully this breaks it down into more bite size nuggets. Mmmm... ViewState Nuggets.
ViewState Nuggets

1. VIEWSTATE STORES VALUES
If you've ever used a hashtable, then you've got it. There's no rocket science here. ViewState has an indexer on it that accepts a string as the key and any object as the value. For example:

ViewState["Key1"] = 123.45M; // store a decimal value
ViewState["Key2"] = "abc"; // store a string
ViewState["Key3"] = DateTime.Now; // store a DateTime

Actually, "ViewState" is just a name. ViewState is a protected property defined on the System.Web.UI.Control class, from which all server controls, user controls, and pages, derive from. The type of the property is System.Web.UI.StateBag. Strictly speaking, the StateBag class has nothing to do with ASP.NET. It happens to be defined in the System.Web assembly, but other than it's dependency on the State Formatter, also defined in System.Web.UI, there's no reason why the StateBag class couldn't live along side ArrayList in the System.Collections namespace. In practice, Server Controls utilize ViewState as the backing store for most, if not all their properties. This is true of almost all Microsoft's built in controls (ie, label, textbox, button). This is important! You must understand this about controls you are using. Read that sentance again. I mean it... here it is a 3rd time: SERVER CONTROLS UTILIZE VIEWSTATE AS THE BACKING STORE FOR MOST, IF NOT ALL THEIR PROPERTIES. Depending on your background, when you think of a traditional property, you might imagine something like this:

public string Text {
    get { return _text; }
    set { _text = value; }
}

What is important to know here is that this is NOT what most properties on ASP.NET controls look like. Instead, they use the ViewState StateBag, not a private instance variable, as their backing store:

public string Text {
    get { return (string)ViewState["Text"]; }
    set { ViewState["Text"] = value; }
}

And I can't stress it enough -- this is true of almost ALL PROPERTIES, even STYLES (actually, Styles do it by implementing IStateManager, but essentially they do it the same way). When writing your own controls it would usually be a good idea to follow this pattern, but thought should first be put into what should and shouldn't be allowed to be dynamically changed on postbacks. But I digress -- that's a different subject. It is also important to understand how DEFAULT VALUES are implemented using this technique. When you think of a property that has a default value, in the traditional sense, you might imagine something like the following:

public class MyClass {
    private string _text = "Default Value!";
 
    public string Text {
        get { return _text; }
        set { _text = value; }
    }
}

The default value is the default because it is what is returned by the property if no one ever sets it. How can we accomplish this when ViewState is being used as the private backing? Like this:

public string Text {
    get {
        return ViewState["Text"] == null ?
             "Default Value!" :
              (string)ViewState["Text"];
    }
    set { ViewState["Text"] = value; }
}

Like a hashtable, the StateBag will return null as the value behind a key if it simply doesn't contain an entry with that key. So if the value is null, it has not been set, so return the default value, otherwise return whatever the value is. For you die-hards out there -- you may have detected a difference in these two implementations. In the case of ViewState backing, setting the property to NULL will result in resetting the property back to it's default value. With a "regular" property, setting it to null means it will simply be null. Well, that is just one reason why ASP.NET always tends to use String.Empty ("") instead of null. It's also not very important to the built in controls because basically all of their properties that can be null already are null by default. All I can say is keep this in mind if you write your own controls. And finally, as a footnote really, while this property-backing usage of the ViewState StateBag is how the StateBag is typically used, it isn't limited to just that. As a control or page, you can access you're own ViewState StateBag at any time for any reason, not just in a property. It is sometimes useful to do so in order to remember certain pieces of data across postbacks, but that too is another subject.

2. VIEWSTATE TRACKS CHANGES
Have you ever set a property on a control and then somehow felt... dirty? I sure have. In fact, after a twelve-hour day of setting properties in the office, I become so filthy my wife refuses to kiss me unless I'm holding flowers to mask the stench. I swear! Ok so setting properties doesn't really make you dirty. But it does make the entry in the StateBag dirty! The StateBag isn't just a dumb collection of keys and values like a Hashtable (please don't tell Hashtable I said that, he's scarey). In addition to storing values by key name, the StateBag has a TRACKING ability. Tracking is either on, or off. Tracking can be turned on by calling TrackViewState(), but once on, it cannot be turned off. When tracking is ON, and ONLY when tracking is ON, any changes to any of the StateBag's values will cause that item to be marked as "Dirty". StateBag even has a method you can use to detect if an item is dirty, aptly named IsItemDirty(string key). You can also manually cause an item to be considered dirty by calling SetItemDirty(string key). To illustrate, lets assume we have a StateBag that is not currently tracking:

stateBag.IsItemDirty("key"); // returns false
stateBag["key"] = "abc";
stateBag.IsItemDirty("key"); // still returns false
 
stateBag["key"] = "def";
stateBag.IsItemDirty("key"); // STILL returns false
 
stateBag.TrackViewState();
stateBag.IsItemDirty("key"); // yup still returns false
 
stateBag["key"] = "ghi";
stateBag.IsItemDirty("key"); // TRUE!
 
stateBag.SetItemDirty("key", false);
stateBag.IsItemDirty("key"); // FALSE!

Basically, tracking allows the StateBag to keep track of which of it's values have been changed since TrackViewState() has been called. Values that are assigned before tracking is enabled are not tracked (StateBag turns a blind eye). It is important to know that any assignment will mark the item as dirty -- even if the value given matches the value it already has!

stateBag["key"] = "abc";
stateBag.IsItemDirty("key"); // returns false
stateBag.TrackViewState();
stateBag["key"] = "abc";
stateBag.IsItemDirty("key"); // returns true

ViewState could have been written to compare the new and old values before deciding if the item should be dirty. But recall that ViewState allows any object to be the value, so you aren't talking about a simple string comparison, and the object doesn't have to implement IComparable so you're not talking about a simple CompareTo either. Alas, because serialization and deserialization will be occuring, an instance you put into ViewState won't be the same instance any longer after a postback. That kind of comparison is not important for ViewState to do it's job, so it doesn't. So that's tracking in a nutshell.

But you might wonder why StateBag would need this ability in the first place. Why on earth would anyone need to know only changes since TrackViewState() is called? Why wouldn't they just utilize the entire collection of items? This one point seems to be at the core of all the confusion on ViewState. I have interviewed many professionals, sometimes with years and years of ASP.NET experience logged in their resumes, who have failed miserably to prove to me that they understand this point. Actually, I have never interviewed a single candidate who has! First, to truly understand why Tracking is needed, you will need to understand a little bit about how ASP.NET sets up declarative controls. Declarative controls are controls that are defined in your ASPX or ASCX form. Here:

<asp:Label id="lbl1" runat="server" Text="Hello World" />

I do declare that this label is declared on your form. The next thing we need to make sure you understand is ASP.NET's ability to wire up declared attributes to control properties. When ASP.NET parses the form, and finds a tag with runat=server, it creates an instance of the specified control. The variable name it assigns the instance to is based on the ID you assigned it (by the way, many don't realize that you don't have to give a control an ID at all, ASP.NET will use an automatically generated ID. Not specifying an ID has advantages, but that is a different subject). But that's not all it does. The control's tag may contain a bunch of attributes on it. In our label example up above, we have a "Text" attribute, and it's value is "Hello World". Using reflection, ASP.NET is able to detect whether the control has property by that name, and if so, sets its value to the declared value. Obviously the attribute is declared as a string (hey, its stored in a text file after all), so if the property it maps to isn't of type string, it must figure out how to convert the given string into the correct type, before calling the property setter. How it does that my friend is also an entirely different topic (it involves TypeConverters and static Parse methods). Suffice it to say it figures it out, and calls the property setter with the converted value.

Recall that all-important statement from the first role of the StateBag. Here it is again: Server Controls utilize ViewState as the backing store for most, if not all their properties. That means when you declare an attribute on a server control, that value is usually ultimately stored as an entry in that control's ViewState StateBag. Now recall how tracking works. Remember that if the StateBag is "tracking", then setting a value to it will mark that item as dirty. If it isn't tracking, it won't be marked dirty. So the question is -- when ASP.NET calls the SET on the PROPERTY that corresponds to the ATTRIBUTE that is DECLARED on the control, is the StateBag TRACKING or isn't it? The answer is no it is not tracking, because tracking doesn't begin until someone calls TrackViewState() on the StateBag, and ASP.NET does that during the OnInit phase of the page/control lifecycle. This little trick ASP.NET uses to populate properties allows it to easily detect the difference between a declaratively set value and dynamically set value. If you don't yet realize why that is important, please keep reading.

3. SERIALIZATION AND DESERIALIZATION
Aside from how ASP.NET creates declarative controls, the first two capabilities of ViewState we've discussed so far have been strictly related to the StateBag class (how it's similar to a hashtable, and how it tracks dirty values). Here is where things get bigger. Now we will have to start talking about how ASP.NET uses the ViewState StateBag's features to make the (black) magic of ViewState happen.

If you've ever done a "View Source" on an ASP.NET page, you've no doubt encountered the serialization of ViewState. You probably already knew that ViewState is stored in a hidden form field aptly named _ViewState as a base64 encoded string, because when anyone explains how ViewState works, that's usually the first thing they mention.

A brief aside -- before we understand how ASP.NET comes up with this single encoded string, we must understand the hierarchy of controls on the page. Many developers with years of experience still don't realize that a page consists of a tree of controls, because all they work on are ASPX pages, and all they need to worry about are controls that are directly declared on those pages... but controls can contain child controls, which can contain their own child controls, etc. This forms a tree of controls, where the ASPX page itself is the root of that tree. The 2nd level is all the controls declared at the top level in the ASPX page (usually that consists of just 3 controls -- a literal control to represent the content before the form tag, a HtmlForm control to represent the form and all its child controls, and another literal control to represent all the content after the close form tag). On the 3rd level are all the controls contained within those controls (ie, controls that are declared within the form tag), and so on and so forth. Each one of the controls in the tree has it's very own ViewState -- it's very own instance of a StateBag. There's a protected method defined on the System.Web.UI.Control class called SaveViewState. It returns type 'object'. The implementation for Control.SaveViewState is to simply pass the call along to the Control's StateBag (it too has a SaveViewState() method). By calling this method recursively on every control in the control tree, ASP.NET is able to build another tree that is structured not unlike the control tree itself, except instead of a tree of controls, it is a tree of data.

The data at this point is not yet converted into the string you see in the hidden form field, it's just an object tree of the data to be saved. Here is where it finally comes together... are you ready? When the StateBag is asked to save and return it's state (StateBag.SaveViewState()), it only does so for the items contained within it that are marked as Dirty. That is why StateBag has the tracking feature. That is the only reason why it has it. And oh what a good reason it is -- StateBag could just process every single item stored within it, but why should data that has not been changed from it's natural, declarative state be persisted? There's no reason for it to be -- it will be restored on the next request when ASP.NET reparses the page anyway (actually it only parses it once, building a compiled class that does the work from then on). Despite this smart optimization employed by ASP.NET, unnecessary data is still persisted into ViewState all the time due to misuse. I will get into examples that demonstrate these types of mistakes later on.

POP QUIZ
If you've read this far, congratulations, I am rewarding you with a pop quiz. Aren't I nice? Here it is: Let's say you have two nearly identical ASPX forms: Page1.aspx and Page2.aspx. Contained within each page is just a form tag and a label, like so:

<form id="form1" runat="server">
    <asp:Label id="label1" runat="server" Text="" />
</form>

They are identical except for one minor difference. In Page1.aspx, we shall declare the label's text to be "abc":

<asp:Label id="label1" runat="server" Text="abc" />

...And on Page2.aspx, we shall declare the label's text to be something much longer (the preamble to the Constitution of the United States of America):

<asp:Label id="label1" runat="server" Text="We the people of the United States,
        in order to form a more perfect union, establish justice, insure
        domestic tranquility, provide for the common defense, promote the
        general welfare, and secure the blessings of liberty to ourselves and
        our posterity, do ordain and establish this Constitution for the United
        States of America." />


Imagine you browse to Page1.aspx, you will see "abc" and nothing more. Then you use your browser to view the HTML source of the page. You will see the infamous hidden _ViewState hidden field with encoded data in it. Note the size of that string. Now you browse to Page2.aspx, and you see the preamble. You use your browser to view the HTML source once again, and you note the size of the encoded _ViewState field. The question is: Are the two sizes you noted the same, or are they different? Before we get to the answer, lets make it a little bit more involved. Lets say you also put a button next to the label (on each page):

<asp:Button id="button1" runat="server" Text="Postback" />


There is no code in the click event handler for this button, so clicking on it doesn't do anything except make the page flicker. With this new button in place, you repeat the experiment, except this time when browsing to each page, you click the Postback button before looking at the HTML source. So the question is once again... Are the encoded ViewState values the same, or different? The correct answer to the first part the question is THEY ARE THE SAME! They are the same because in neither of the two ViewState strings are any data related to the label at all. If you understand ViewState, this is obvious. The Text property of the label is set to the declared value before it's ViewState is being tracked. That means if you were to check the dirty flag of the Text item in the StateBag, it would not be marked dirty. StateBag ignores items that aren't dirty when SaveViewState() is called, and it is the object it returns that is serialized into the hidden _ViewState field. Therefore, the text property is not serialized. Since the Text is not serialized in either case, and the forms are identical in every other way, the sizes of the encoded ViewStates on each page must be the same. In fact, no matter how large or small of a string you stuff into that text attribute, the size will remain the same.

The correct answer to the second part is again, THEY ARE THE SAME! In order for data to be serialized, it must be marked as dirty. In order to be marked as dirty, it's value must be set after TrackViewState() is called. But even when we perform a postback, ASP.NET recreates and populates the server controls in the same way. The Text property is still set to it's declared value just like it was in the first request. No other code is setting the text property, so there's no way the StateBag item could become dirty, even on a postback. Therefore, the sizes of the encoded ViewStates on each page after a postback must be the same.

So now we understand how ASP.NET determines what data needs to be serialized. But we don't know how it is serialized. That topic is outside the scope of this article (are you missing an assembly reference?), so if you're really interested in how it works, read up on the LosFormatter for ASP.NET 1.x or the ObjectStateFormatter for ASP.NET 2.0.

Finally on this topic is DESERIALIZATION. Obviously all this fancy dirty tracking and serialization wouldn't do any good if we couldn't get the data back again. That too is outside the scope of this article, but suffice it to say the process is just the reverse. ASP.NET rebuilds the object tree it serialized by reading the posted _ViewState form value and deserializing it with the LosFormatter (v1.x) or the ObjectStateFormatter (v2.0).

4. AUTOMATICALLY RESTORES DATA
This is last on our list of ViewState features. It is tempting to tie this feature in with Deserialization above, but it is not really part of that process. ASP.NET deserializes the ViewState data, and THEN it repopulates the controls with that data. Many articles out there confuse these two processes.

Defined on System.Web.UI.Control (again, the class that every control, user control, and page derive from) is a LoadViewState() method which accepts an object as parameter. This is the opposite of the SaveViewState() method we already discussed, which returns an object. Like SaveViewState(), LoadViewState() simple forwards the call on to it's StateBag object, calling LoadViewState on it. The StateBag then simply repopulates it's key/object collection with the data in the object. In case you are wondering, the object it is given is a System.Web.UI.Pair class, which is just a simple type with a First and Second field on it. The "First" field is an ArrayList of key names, and the "Second" field is an ArrayList of values. So StateBag just iterates over the lists, calling this.Add(key, value) for each item. The important thing to realize here is that the data it was given via LoadViewState() are only items that where marked dirty on the previous request. Prior to loading the ViewState items, the StateBag may already have values in it. Those values may be from declarative properties like we discussed, but they may also be values that were explicitly set by the developer prior to the LoadViewState call. If one of the items passed into LoadViewState already exists in the StateBag for some reason, it will be overwritten.

That right there is the magic of automatic state management. When the page first begins to load during a postback (even prior to initialization), all the properties are set to their declared natural defaults. Then OnInit occurs. During the OnInit phase, ASP.NET calls TrackViewState() on all the StateBags. Then LoadViewState() is called with the deserialized data that was dirty from the previous request. The StateBag calls Add(key, value) for each of those items. Since the StateBag is tracking at this point, the value is marked dirty, so that it may be persisted once again for the next postback. Brilliant! Whew. Now you are an expert on ViewState management.

IMPROPER USE OF VIEWSTATE
Now that we know exactly how ViewState works, we can finally begin to understand the problems that arise when it is used improperly. In this section I will describe cases that illustrate how a lot of ASP.NET developers misuse ViewState. But these aren't just obvious mistakes. Some of these will illustrate nuances about ViewState that will give you an even deeper understanding of how it all fits together.
    CASES OF MISUSE
  1. Forcing a Default
  2. Persisting static data
  3. Persisting cheap data
  4. Initializing child controls programmatically
  5. Initializing dynamically created controls programmatically
1. Forcing a Default
This is one of the most common misuses, and it is also the easiest to fix. The fixed code is also usually more compact than the wrong code. Yes, doing things the right way can lead to less code. Imagine that. This usually occurs when a control developer wants a particular property to have a particular default value, and does not understand the dirty tracking mechanism, or doesn't care. For example, lets say the Text property a control is supposed to be some value that comes from a Session variable. Developer Joe writes the following code:

public class JoesControl : WebControl {
    public string Text {
        get { return this.ViewState["Text"] as string; }
        set { this.ViewState["Text"] = value; }
    }
 
    protected override void OnLoad(EventArgs args) {
        if(!this.IsPostback) {
            this.Text = Session["SomeSessionKey"] as string;
        }
 
        base.OnLoad(e);
    }
}

This developer has committed a ViewState crime, call the ViewState police! There's two big problems with this approach. First of all, since Joe is developing a control, and he has taken the time to create a public Text property, it stands to reason that Joe may want developers that use his control to be able to set the Text property to something else. Jane is a page developer that is attempting to do just that, like so:

<abc:JoesControl id="joe1" runat="server" Text="ViewState rocks!" />

Jane is going to have a bad day. No matter what Jane puts into that Text attribute, Joe's control will refuse to listen to her. Poor Jane. She's using this control just like you use every other ASP.NET control, but this one works differently. Joe's control is overwriting Jane's Text value! Worse than that, since Joe sets it during the OnLoad phase, it is marked dirty in ViewState. So to add insult to injury, Jane is now incurring an increase in her page's serialized ViewState size for doing nothing more than putting Joe's Control on her page. I guess Joe doesn't like Jane very much. Maybe Joe's just trying to get back at Jane for something. Well, since we all know which sex rules this world, we can assume Jane ends up getting Joe to fix his control. Much to Jane's delight, this is what Joe comes up with:

public class JoesControl : WebControl {
    public string Text {
        get {
            return this.ViewState["Text"] == null ?
                Session["SomeSessionKey"] :
                this.ViewState["Text"] as string;
        }
        set { this.ViewState["Text"] = value; }
    }
}

Look at how much less code we have here. Joe doesn't even have to override OnLoad. Because the StateBag returns null if the given key does not exist, Joe can detect whether his Text property has been set already by checking for null. If it is, he can safely return his would-be default value. If it's not null, he happily returns whatever value it is. Simple as can be. Now when Jane uses Joe's control, not only is her Text attribute honored, she no longer incurs a hit on her ViewState size, either. Better behavior. Better performance. Less code. Everyone wins!

2. Persisting static data
By Static, I mean data that never changes or is not expected to change during the lifetime of a page, or even during the users session. Lets say Joe, our would-be shoddy asp.net developer, has been tasked with adding the current user's name to the top of a page in the company's eCommerce application. It's a nice way of telling the user, "hey, we know who you are!" It makes them feel special and that the site is working. Positive feedback. Lets say this eCommerce application has a business layer API that allows Joe to easily get the name of the currently authenticated user: CurrentUser.Name. Joe completes his task:

(ShoppingCart.aspx)
<asp:Label id="lblUserName" runat="server" />


(ShoppingCart.aspx.cs)
protected override void OnLoad(EventArgs args) {
    this.lblUserName.Text = CurrentUser.Name;
    base.OnLoad(e);
}

Sure enough, the current user's name will show up. Piece of cake, Joe thinks. Of course we know Joe has committed another sin. The label control he is using is tracking it's ViewState when it is assigned the current user's name. That means not only will the Label render the user name, but that user name will be encoded into the ViewState hidden form field. Why make ASP.NET go through all the work of serializing and deserializing the user name, when you are just going to reassign it after all? That's just rude! Even when confronted, Joe shrugs at the problem. It's only a few bytes! But it's a few bytes you can save so easily. There are two solutions to this problem. First... you could just disable ViewState on the label.

<asp:Label id="lblUserName" runat="server" EnableViewState="false" />

Problem solved. But there's an even better solution. Label has to be one of the most overused controls there are, bested only by the Panel control. It comes from the mindset of Visual Basic Programmers. To show text on a VB Form you needed a label. Labels are supposed to be the ASP.NET WebForm counterpart, so it's only nature to think you need a label to display a text value that isn't hardcoded in the webform. Fair enough, but that's not true. Label's render a <span> tag around their text content. You must ask yourself whether your really need this span tag at all. Unless you are applying a STYLE to this label, the answer is NO. This would suffice just fine:

<%= CurrentUser.Name %>

Not only do you get to avoid having to declare a label on the form (which means less code, albeit designer-generated code), but you've followed the spirit of the code-behind model: separation of code from design! In fact, if Joe's company had a dedicated designer responsible for the look and feel of the eCommerce site, Joe could have simply passed on the task. "That's the designers job", he could have balked, and rightfully so. There is another reason why you might THINK you need a Label, and that is when something in the code behind may need to programmatically access or manipulate that label. Ok, fair enough. But you must still ask yourself whether you really need a SPAN tag surrounding the text. Introducing the most underused control in ASP.NET: The LITERAL!

<asp:Literal id="litUserName" runat="server" EnableViewState="false"/>

No span tag here.

3. Persisting cheap data
This one is a superset of #2. Static data is definitely cheap to get. But not all cheap data is static. Sometimes we have data that may change during the lifetime of an application, possibly from moment to moment, but that data is virtually free to retrieve. By free, I mean the performance cost of looking it up is insignificant. A common instance of this mistake is when populating a dropdown list of U.S. States. Unless you are writing a web application that you plan on warping back in time to December 7, 1787 (here), the list of US States is not going to change any time soon. However, as a programmer that hates to type, you certainly wouldn't want to have to type these states by hand into your web form. And in the event a state does rebel (we can only dream... you know who you are), you wouldn't want to have to perform a code change to strike it from the list. Our proverbial programmer Joe decides he will populate his dropdown list from a USSTATES table in a database. The eCommerce site is already using a database, so its trivial for him to add the table and query it.

<asp:DropdownList id="lstStates" runat="server"
    DataTextField="StateName" DataValueField="StateCode" />

protected override void OnLoad(EventArgs args) {
    if(!this.IsPostback) {
        this.lstStates.DataSource = QueryDatabase();
        this.lstStates.DataBind();
    }
    base.OnLoad(e);
}

As is the nature of databound controls in ASP.NET, the state dropdown will be using ViewState to remember it's databound list of list items. At the time of this ranting, there are a total of 50 US States. Not only does the dropdown list contain a ListItem for each and every state, but each and every one of those states and their state codes are being serialized into the encoded ViewState. That's a lot of data to be stuffing down the pipe every time the page loads, especially over a dialup connection. I often wonder what it would be like if I explained to my grandmother the reason why her internet is so slow is because her computer is telling the server what all the US States are. I don't think she'd understand. She'd probably just start explaining how when she was young, there were only 46 states. Too bad... those extra 4 states are really wearing down your bandwidth. Damn you late comers! You know who you are!

Like the problem with static data, the general solution to this problem is to just disable ViewState on the control. Unfortunately, that is not always going to work. Whether it does depends on the nature of the control you are binding, and what features of it you are dependant on. In this example, if Joe simply added EnableViewState="false" to the dropdown, and removed the if(!this.IsPostback) condition, he would successfully remove the state data from ViewState, but he would immediately run into a troubling problem. The dropdown will no longer restore it's selected item on postbacks. WAIT!!! This is another source of confusion with ViewState. The reason the dropdown fails to remember it's selected item on postbacks is NOT because you have disabled ViewState on it. Postback controls such as dropdownlist and textbox restore their posted state (the selected item of a dropdown ist 'posted') even when ViewState is disabled, because even with ViewState disabled the control is still able to post its value. It forgets it's selected value because you are rebinding it in OnLoad, which is after the dropdown has already loaded it's posted value. When you databind it again, the first thing it does is throw that into the bit bucket (you know, digital trash). That means if a user selects California from the list, then click on a submit button, the dropdown will stubbornly return the default item (the first item if you don't specify it otherwise). Thankfully, there is an easy solution: Move the DataBind into OnInit:

<asp:DropdownList id="lstStates" runat="server"
    DataTextField="StateName" DataValueField="StateCode" EnableViewState="false" />

protected override void OnInit(EventArgs args) {
    this.lstStates.DataSource = QueryDatabase();
    this.lstStates.DataBind();
    base.OnInit(e);
}

The short explanation for why this works: You are populating the dropdown list with items before it attempts to load it's posted value. Now the dropdown will behave just like it did when Joe first designed it, only the rather large list of states will NOT be persisted into the ViewState hidden field! Brilliant! More importantly, this rule applies to any data that is cheap and easy to get to. You might argue that making a database query on every request is MORE costly than persisting the data through ViewState. In this case I believe you'd be wrong. Modern database systems (say, SQL Server) have sophisticated caching mechanism and are extremely efficient if configured correctly. The state list needs to be repopulated on every request no matter what you're doing. All you've done is change it from being pushed and pulled down a slow, unreliable 56kbps internet connection that may have to travel for thousands of miles, to being pulled over at worse a 10 megabit LAN connection a couple hundred feet between your internet server and database server. AND if you really wanted to improve things, you could cache the results of the database query in the application. You do the math!

4. Initializing child controls programmatically
Let's face it. You can't do everything declaratively. Sometimes you have to get logic involved. That's why we all have jobs, right? The trouble is ASP.NET does not provide an easy way to programmatically initialize properties of child controls correctly. You can override OnLoad and do it there -- but then you're persisting data that probably doesn't need to be persisted into ViewState. You can override OnInit and do it there instead, but that suffers from the same problem. Remember when we learned how ASP.NET calls TrackViewState() during the OnInit phase? It does this recursively on the entire control tree, but it does it from the BOTTOM of the tree UP! In other words, as a control or webform, the OnInit phase of your child controls occurs BEFORE your own. A control will begin tracking ViewState changes in this phase, which means by the time your own OnInit phase begins, your child controls ViewState are all already tracking! Lets say Joe would like to display the current date and time in a label declared on the form.

<asp:Label id="lblDate" runat="server" />

protected override void OnInit(EventArgs args) {
    this.lblDate.Text = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss");
    base.OnInit(e);
}

Even though Joe is setting the label text in the earliest event possible on his webform, it's already too late. The label is tracking ViewState changes, and the current date and time will inevitably be persisted into ViewState. This particular example could fall under the cheap data issue above. Joe could simply disable ViewState on the label to solve this problem. But here we are going to solve it a different way in order to illustrate an important concept. What would be nice is if Joe could declaratively set the label text to what he wants, something like:

<asp:Label id="Label1" runat="server" Text="<%= DateTime.Now.ToString() %>" />

You may have intuitively attempted this before. But ASP.NET will slap you in the face for it. The "<%= %>" syntax can not be used to assign values to properties of server-side controls. Joe could use the "<%# %>" syntax instead, but that isn't very different than the databinding method we've already covered (disabling ViewState and databinding it every request). The problem is we would like to be able to assign a value through code, but allow the control to continue to work in exactly the way it normally would. Perhaps some code is going to be manipulating this label, and we want any changes made to it to be persisted through ViewState like they normally would be. For example, maybe Joe wants to give the users a way to remove the date display from the form, replacing it with a blank date instead:

private void cmdRemoveDate_Click(object sender, EventArgs args) {
    this.lblDate.Text = "--/--/---- --:--:--";
}

If the user clicks this button, the current date and time will vanish. But if we solved our original ViewState problem by disabling ViewState on the label, the date and time will magically reappear again on the next postback that occurs, because the label's ViewState being disabled means it will not automatically be restored. That's not good. What on Earth is Joe supposed to do now?

What we really want is to declaratively set a value that is based on logic, not static. If it were declared the label could continue to work like it normally does -- the initial state wouldn't be persisted since it is set before ViewState is tracking, and changes to it would be persisted in ViewState. Like I said... ASP.NET does not provide an easy way to accomplish this task. For you ASP.NET 2.0 developers out there, you do have the $ sign syntax, which allows you to use expression builders to declare values that actually come from a dynamic source (ie, resources, declared connection strings). There's no expression builder for "just run this code" so I don't think that helps you either (UPDATE: Unless you use my custom CodeExpressionBuilder!). Also for ASP.NET 2.0 developers, there's OnPreInit. That is actually a great place to initialize child control properties programmatically because it occurs before the child control's OnInit (and therefore before it is tracking ViewState) and after the controls are created. However, OnPreInit is not recursive like the other control phase methods are. That means it is only accessible on the PAGE itself. That doesn't help you what-so-ever if you are developing a CONTROL. It's too bad OnPreInit isn't recursive just like OnInit, OnLoad, and OnPreRender are, I don't see a reason for the inconsistency. The root of the problem is simply that we need to be able to assign the Text property of the label BEFORE it begins tracking its ViewState. We already know the page's OnInit event (the first event that occurs in the page) is already too late for that. So what if we could somehow hook into the Init event of the label? You can't add an event handler in code for that, because the soonest you can do it is in your OnInit which is after the source event has already occurred. And you can't do it in the constructor for the page, because declared controls are not yet created at that point. There are two possibilities:

1. Declaratively hook into the Init event:
<asp:Label id="Label2" runat="server" OnInit="lblDate_Init" />

This works because the OnInit attribute is processed before the label's own OnInit event occurs, giving us an opportunity to manipulate it before it beings tracking ViewState changes. Our event handler would set its text.

2. Create a custom control:
public class DateTimeLabel : Label {
    public DateTimeLabel() {
        this.Text = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss");
    }
}

Then instead of a regular label on the form, a DateTimeLabel is used. Since the control is initializing it's own state, it can do so before tracking begins. It does it during the constructor if possible, so that a declared value will be honored.

5. Initializing dynamically created controls programmatically
This is the same problem as before, but since you are in more control of the situation, it is much easier to solve. Lets say Joe has written a custom control that at some point is dynamically creating a Label.

public class JoesCustomControl : Control {
    protected override void CreateChildControls() {
        Label l = new Label();
 
        this.Controls.Add(l);
        l.Text = "Joe's label!";
    }
}

Hmmm. When do dynamically created controls begin tracking ViewState? You can create and add dynamically created controls to your controls collection at almost any time during the page lifecycle, but ASP.NET uses the OnInit phase to start ViewState tracking. Won't our dynamic label miss out on that event? No. The trick is, Controls.Add() isn't just a simple collection add request. It does much more. As soon as a dynamic control is added to the control collection of a control that is rooted in the page (if you follow its parent controls eventually you get to the page), ASP.NET plays "catch up" with the event sequence in that control and any controls it contains. So let's say you add a control dynamically in the OnPreRender event (although there plenty of reasons why you would not want to do that). At that point, your OnInit, LoadViewState, LoadPostBackData, and OnLoad events have transpired. The second the control enters your control collection, all of these events happen within the control.

That means my friends the dynamic control is tracking ViewState immediately after you add it. Besides your constructor, the earliest you can add dynamic controls is in OnInit, where child controls are already tracking ViewState. In Joe's control, he's adding them in the CreateChildControls() method, which ASP.NET calls whenever it needs to make sure child controls exist (when it is called can vary based on whether you are an INamingContainer, whether it is a postback, and whether anything else calls EnsureChildControl()). The latest this can happen is OnPreRender, but if it happens any time after or during OnInit, you will be dirtying ViewState again, Joe. The solution is simple but easy to miss:

public class JoesCustomControl : Control {
    protected override void CreateChildControls() {
        Label l = new Label();
        l.Text = "Joe's label!";
 
        this.Controls.Add(l);
    }
}

Subtle. Instead of initializing the label's text after adding it to the control collection, Joe initializes it before it is added. This ensures without a doubt that the Label is not tracking ViewState when it is initialized. Actually you can use this trick to do more than just initialize simple properties. You can databind controls even before they are part of the control tree. Remember our US State dropdown list example? If we can create that dropdown list dynamically, we can solve that problem without even disabling its ViewState:

public class JoesCustomControl : Control {
    protected override void OnInit(EventArgs args) {
        DropDownList states = new DropDownList();
        states.DataSource = this.GetUSStatesFromDatabase();
        states.DataBind();
 
        this.Controls.Add(states);
    }
}


It works amazingly well. The dropdown list will behave as if the states are simply built-in list items. They are not persisted in ViewState, yet ViewState is still enabled on the control, meaning you can still take advantage of its ViewState dependant features like the OnSelectedIndexChanged event. You can even do this with DataGrids, although that depends on how you are using it (you will run into problems if you are using sorting, paging, or using the SelectedIndex feature).

BE VIEWSTATE FRIENDLY
Now that you have a complete understanding of how ViewState does it's magic, and how it interacts with the page lifecycle in asp.net, it should be easy to be ViewState Friendly! That is the key really... ViewState optimization is easy as pie when you understand what is going on, often times resulting in even less code than the non-friendly code. Have any suggestions, comments, error reports? Please leave a comment or send me an email!

UPDATE 02/19/2008: Take a look at TRULY Understanding ViewState, the Comment Index!

260 Comments

  • Thanks for taking time to write this, it really helped to clear up some problems I was having getting an understanding of what ViewState was doing. I'd also be grateful if the page rendered correctly in Firefox, it was annoying having to fire up IE to read it :^).

  • "ViewState is not responsible for the population of values that are posted such as by TextBox"

    DOT.NET 1.1
    Suppose I have 2 user controls (let's call them G and F) on a page one containing a gridview one containing some textboxes.

    G is visible , F is not.
    When linkbutton detail in grid is clicked, G becomes invisible, F becomes visible and loads data (using databinding) for the selected row. Click save and G becomes visible, F invisible.

    Click New button on G, then G becomes invisible, F visible, there is NO databinding, so I would have expected empty textboxes in F, but previous values show up.

    These values could not have come from POSTing data, as the F control was invisible, and thus was not rendered. So values of textboxes on a control that is invisible are stored in ViewState ?

  • An interesting article! Shorter paragraphs and fewer attempts at humor would make it much more readable though.

    One thing I'd like to challenge you on is your advice on using OnInit to avoid dirtying the ViewState when initializing the States example (chapter 3 of the misuse part). Right after that in chapter 4 you state that initializing the formatted DateTime in OnInit is too late, since the label is already tracking its ViewState. There is apparent controversy between these two chapters. What are your thoughts on this, and what have you intended to say in chapter 3?

  • sclough -- It should look fine in FF now, thanks for the heads up. I had just spent a few hours tweaking the UI and didn't get a chance to review it in FF. At least you were polite about it. You wouldn't believe some of the mail I got from FF users. Chill out guys :) It's not a war. Its a browser.

  • rekna -- yes exactly. ViewState is important in a textbox if you want its value to be maintained even if the textbox is not visible for a while. It's also important if you want to use the TextChanged event since the way it knows whether the event should fire is by comparing its posted value to its viewstate value. Without ViewState it will always think it has changed (unless the value is blank) and so will always fire the event.

    That being said, its still primarily the POST nature of the control that maintains its value. Thats why when you disable viewstate, it will still recall its value on a postback.

    In 2.0 (not entirely sure if this is true of 1.1 but I think so) -- the textbox tries to be smarter about whether viewstate should be utilized. If you don't hook into the TextChanged event, the TextBox isn't "disabled" (to appear greyed out), and it is Visible, then there's no reason to pollute viewstate, and so it doesn't... automatically.

  • Jouni --

    I thought the humor would make it easier to read :) Can't please everyone I suppose. As for the paragraph lengths -- yes, I'm guilty of that. I do plan on revamping this article in the future and expanding on the examples at the end, so I appreciate the feedback.

    OnInit -- actually there's no controversey really. In the Dropdown example not only did I suggest binding in OnInit, but I said to disable viewstate on the control. ViewState for child controls is indeed tracking in OnInit. It is not tracking for your OWN viewstate though. You can see it for yourself if you put a break point in OnInit and do a watch on something like:

    this.ViewState.IsTrackingViewState // false
    this.Controls[0].IsTrackingViewState // true

    In the DateTime example I tried to initialize a label in OnInit, but _without_ disabling its viewstate. I hope that clears it up.

    Thanks for the comment :)

  • All right, I accept that :-)
    Re humor: I didn&#39;t have a problem reading your article, but writers of definitive tutorials (&quot;TRULY understanding ViewState&quot; sounds like one) should remember that non-native English speakers have considerably more trouble discerning the facts when entwined with witty remarks.
    For this reason, I recommend either removing the humor or putting it in a sidebar (of course, not all jokes work that way). This way readers can easily identify it as optional content and focus their understanding on the factual parts. I&#39;ll say the same for most IT books as well - and it&#39;s not like I&#39;m opposed to humor in general at all :-)

  • Noted, killjoy!

    http://dictionary.reference.com/browse/killjoy

    j/k

    Thanks for the feedback :)

  • In your text you say &quot;Also for ASP.NET 2.0 developers, there&#39;s OnPreInit. That is actually a great place to initialize child control properties programmatically because it occurs before the child control&#39;s OnInit (and therefore before it is tracking ViewState) and after the controls are created. &quot;
    This is not working for me. If I override OnPreInit on a page the controls have not been created. They are all null.
    Otherwise, thanks for a great article!

  • Calle -- are you using a master page? Try calling base.OnPreInit, then check the controls, they should be there.

    Thanks for reading :)

  • I tried without a master page and then it worked. Why will it not work with at master page?

  • Master pages cause the controls to be shuffled around a bit during initialization. Did you try calling base.OnPreInit first?

  • Yes. Here is the code:
    &nbsp; &nbsp;protected override void OnPreInit(EventArgs e)
    &nbsp; &nbsp;{
    &nbsp; &nbsp; &nbsp; &nbsp;base.OnPreInit(e);
    &nbsp; &nbsp; &nbsp; &nbsp;Label1.Text = &quot;Test&quot;; // Crashes here with NullPointerException
    &nbsp; &nbsp;}

  • GSR -- Are the controls you are creating textboxes or other form controls (like dropdownlist)? You have to realize that these controls are designed to maintain the value entered by the user. The value you assign the control before you add it to the control collection is only meant to be a "starting" value. This can be illustrated if you declare a TextBox statically on the form and assign it a Text value. When the page first renders you see the value you gave it declaratively. But if you change the value as a user, then do a postback, your value remains, not the declared value. That is what it is _supposed_ to do. It sounds like you want to force the textbox value to your own value, potentially overwriting whatever the user entered, is that correct?

    If thats the case, I highly recommend you change to creating the controls in OnInit. Then in Load you can assign the value you want, just as if it weren't a dynamic control at all. This works because by creating it in OnInit, you give the textbox the opportunity to load its posted value in the natural way (at the same time all the other controls do, before Load). When you don't create the control until Load, it misses that opportunity, and participates in the 2nd and last chance to load posted values which is after Load. Since its after Load its overwriting your assigned value.

    In general its always better to separate the creation of a dynamic control and dynamic changes to it, ala OnInit and Load.

    I hope that solves your problem... sounds like it should.
    -Dave

  • Calle -- I haven't had a chance to test this out. I know I've done it that way before, but perhaps there's something different about your master page setup that is yielding different behavior. May I ask why you need to initialize the control there? There's usually another/better way.

  • Thanks!! Problem solved. Your suppositions were right. I had three textboxes and I wanted to overwrite their values.
    Very thankful by the received aid.

  • Can you please tell how to manage view state in callback events?
    Because life cycle of the page is not same as PostBack!

  • Kalpesh -- the life cycle is similar. It does get cut short because there's no point in PreRender or Render (there's nothing to render to). Viewstate and postback data are all still processed as normal though.

    The one thing thats different about a callback is that the data which is posted is representative of the form at the time it was rendered on the browser. For example, if a textbox has value 'foo', the page will load with 'foo' in the box. If the user changes the value to 'bar', and then before doing another postback a callback occurs, the value posted in the callback data is 'foo'. There's a way to update the data so it represents the current state of the form instead if thats what you require. What issue are you having?

  • Steve,

    Thanks for the comment. I think I need more context about your problem. You have a page that is opening an additional popup window (to another page I presume), and upon doing so it posts back? Maybe some code samples would make it more clear.

  • Sorry for the lack of details... I&#39;m not sure which code samples might be beneficial so here goes.
    A Main Page contains a variety of info and controls, one button is uxTestEmailButton which is an asp:button. &nbsp;The following code is used to establish the PostBack &amp; handle the popup...
    &nbsp; &nbsp; &nbsp; &nbsp;string emailInfoScript = string.Format(&quot;ShowEmailInfo()&quot;);
    &nbsp; &nbsp; &nbsp; &nbsp;string emailInfoUrl = Page.ClientScript.GetPostBackEventReference(this, &quot;&quot;);
    &nbsp; &nbsp; &nbsp; &nbsp;uxTestEmailButton.OnClientClick = emailInfoUrl.Replace(&quot;&#39;&#39;&quot;, emailInfoScript);
    ShowEmailInfo is javascript which launches the popup window with the new page. &nbsp;The popup page gathers User specific information to be included in the &quot;TestEmail&quot;. &nbsp;When a save / close button is selected on this popup, the ShowEmailInfo function captures the information and returns it.
    The RaisePostBackEvent(string eventArgument) is received when ShowEmailInfo function returns and the eventArgument contans the return value from the ShowEmailInfo.
    function ShowEmailInfo()
    {
    &nbsp; &nbsp;var invokeString = &#39;../Dialogs/EmailInfo.aspx&#39;;
    &nbsp; &nbsp;var returnValue = window.showModalDialog(invokeString, &#39;&#39;, &#39;dialogHeight: 700px; dialogWidth: 800px; resizable: yes; scroll: yes; status: no;&#39;);
    &nbsp; &nbsp;if (returnValue == null)
    &nbsp; &nbsp;{ returnValue = &#39;&#39;; }
    &nbsp; &nbsp;else
    &nbsp; &nbsp;{ returnValue = &#39;EMAIL:&#39; + returnValue; }
    &nbsp; &nbsp;return returnValue;
    }
    Sequence of events:
    Main Page
    Click TestEmail
    ShowEmailInfo javascript function runs
    Poup comes up
    Fill in info in popup
    click button on popup
    popup closes
    ShowEmailInfo javascript gets return info from popup
    ShowEmailInfo javascript returns
    Main page postback received
    Hope this provides a bit more context.
    Steve

  • Steve, I think you are getting two postbacks because of the way you are hooking up that click event. An ASP:Button does a postback naturally, because its a type="submit" button. But you've hooked up client script that runs when it is clicked, which also does a postback via the PostBackEventReference you are using. Hence, clicking the button causes two postbacks. I haven't tested it to see if thats the case (one would think the first postback would stop page processing, but I'm not sure if that's true).

    Whenever you need a link or button that just runs script and nothing else consider using a non-webcontrol like an HtmlButton control, which don't cause postbacks naturally. Or, you can "cancel" the natural postback caused by clicking the button by returning false in the client click script.

    In other words, go ahead and set the OnClientClick code, but be sure and end it with a "return false". Like this...

    uxTestEmailButton.OnClientClick = emailInfoUrl.Replace("''", emailInfoScript) + ";return false;";

    If that's the problem then great. But it goes to show what a scapegoat viewstate has become... everyone assumes their problem is a viewstate issue. I assure you, viewstate works perfectly. :)

    If that doesn't help then we're figure it out... but it still won't be a viewstate problem. Let me know ;)

  • That resolved my issue. &nbsp;It makes perfect sense, but then again hindsight is 20/20.
    Thanks again, the article really helped and even more so for the latest thought.
    Steve

  • Simply Awesome. Thanks for taking time to post this information.

  • Wow! You saved my life.
    Well... almost! :-)

  • Wow... I haven't heard that one before. :)

    Why only almost? :(

  • Great article!! I just wantet to say keep the humor! It did make the article it easier to read, and it also &quot;stimulates&quot; the brain in a different way, making it easier to remember the material. This princible is used in the &quot;Head First&quot; book series. Great books, unfortantly Java based :(
    I don&#39;t believe many non-native English have a problem with your humor (I&#39;m a non-native English), because you need to have a certain English skill to even try to read articles like these.

  • Many thanks for writing the best ASP.NET article ever! I always come back to this post for guidance when developing my controls &amp; pages.

  • Dear Lord Fetta Cheesabio IV of Denver,

    Generally its best to separate the creation of controls from the injection of dynamic data into them. You can't do both at the same time because when you are creating controls, they nor any of the other controls on the page have been updated with the dynamic state of the page. So in other words, _dont_ depend on the country SelectedValue during the creation of the State list.

    The pattern you want to follow is to (1) create the controls as early as you can (OnInit is a good start) and then (2) separately, load/populate/initialize/whateveryoucallit as early as you can. In your case the earliest you can create the controls is OnInit -- but you can't populate the state list yet since the country list hasn't been updated with its posted/selected value. That happens by OnLoad, so that is where you must populate the state list, using the selected value. But you must take care to only do this initialization when the country value changes (if you rebind it every time you'll revert its selected value to the first item). Since the list will use viewstate to remember the items that were databound to it, all is well. But going on --- if you are populating the list manually before adding it to the control collection, or if you have disabled viewstate on it, then it wont rembmer them all you'll be forced to populate it all the time. To avoid the problem of overwriting the posted/selected value in this case, avoid creating it until OnLoad as well. By delaying its creation you stall it from loading the posted value until after OnLoad. And finally -- the next problem you'd have is that in this case, after switching countries, the list will attempt to load a posted value which doesnt exist in the list and so will throw an exception. To avoid that, you give the list an ID that is based on the country list's selected value. That way when the country changes, the new state list has a new identity and won't try to load the previous lists' posted value.

    Whew... I kind of rambled there but I hope it sheds some light on your situation. You picked a sort of complex scenario to have a problem with.

    The real underlying problem if you ask me is that you are creating the controls dynamically. If you make them static again via a Repeater, all the issues I just rambled on about go away. Doing things dynamically when there's a static way to do it just makes things more complex than they need to be.

    ...And its problems like these that have motivated me to write the articles I'm working on about dynamic controls. If you have a problem like this or any problem with Dynamic Controls (even if you think the problem is with ViewState), please read them.

  • In solution #2 for problem #4 you give the following code:
    public class DateTimeLabel : Label
    { &nbsp; &nbsp;
    &nbsp;public DateTimeLabel()
    &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp;
    &nbsp; &nbsp;this.Text = DateTime.Now.ToString(&quot;MM/dd/yyyy HH:mm:ss&quot;); &nbsp; &nbsp;
    &nbsp;}
    }
    Could this also be done like this?
    public class DateTimeLabel : Label
    { &nbsp; &nbsp;
    &nbsp;protected override void OnInit(EventArgs e)
    &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp;
    &nbsp; &nbsp;this.Text = DateTime.Now.ToString(&quot;MM/dd/yyyy HH:mm:ss&quot;); &nbsp;
    &nbsp; &nbsp;base.OnInit(e);
    &nbsp;}
    }
    Would overriding the OnInit method work?

  • Rahul -- you could do that, and it would work fine. But you'd be overwriting any text value that a user of your control provides declaratively, because declared attributes are assigned before OnInit. Doing it in the constructor is a way of providing a default value that can be overwriten by any of the usual means.

  • TBD -- I'm not sure what you mean you can see the values in clear text. You said you are on an entirely different page. How are you transferring from login.aspx to default.aspx? Is it a Response.Redirect or Transfer? If it's a transfer, the target page can access the posted values from the previous page, because its all done within one request. If you don't like that, do a redirect instead. It's got nothing to do with ViewState, unless I'm not understanding your problem. Let me know.

  • Maybe just slightly off topic but....
    Any thoughts/comments on use of a &quot;custom&quot; or &quot;personal&quot; statebag.
    There have been many times that I wanted to store one or more custom values in &quot;viewstate&quot; but did not want to turn viewstate on. &nbsp;
    I realize you can store these values in hidden form fields, but it would be nice if you dealt with this custom data the same way as if you were placing it in the page&#39;s builtin viewstate, ie serialization, encryption, tamperproof, etc.
    I tend to keep viewstate turned OFF unless it is absolutely necessary (and with the new ControlState, that is almost never the case.
    I see that the statebag object in flagged as Not Inheritable.

  • Mark -- Even if you could inherit from StateBag, I don't think it would help.

    There's a couple of ways you could do it... one, you could NOT turn off viewstate. Instead, wrap all your controls in a PlaceHolder which does have viewstate disabled. Then you can just use the page's viewstate (or the user controls, whichever you are) to store stuff in ViewState, but still have viewstate essentially disabled on all the controls on the page or control (disabling viewstate on a control disables it for all its children too).

    Another way is you could use ControlState. You'd have to write a custom control to let you do it though. It would be like a ControlStateHelper control, could be useful for other purposes. Not trivial to write though.

    It's good that you turn off ViewState by default, but I actually wouldn't recommend that practice, at least not if its only because you want to avoid the fluff. A well written, correctly written page will only use viewstate when it really needs to, even if its enabled. So turning it off just allows you to be "lazy" and do things that wouldn't be good if it were on. You're letting your ViewState muscles get atrophy :(

  • kmobarra -- Just keep in mind you must load the user control on every request. If you load the "next" user control when the user clicks "next", thats fine. But then on the next postback the control is gone and won't process the results, unless you load it again. To do that you can just remember which step you are in within this wizzard, and make sure you load the appropriate user control. So imagine you are on step 1, and Step1.ascx is loaded. The user clicks 'next'. In OnLoad or LoadViewState, you realize you're on step 1 still, so you load Step1.ascx again. Then the next_click event fires. You remove Step1.ascx from the page (you probably put it into a placeholder), then load Step2.ascx, and update the step # you are on. The next postback that occurs, Step2.ascx will load instead.

    If you follow this pattern the controls will maintain their state automatically. There's no magic to be done.

    As for them sharing the "big picture"... the driver of this page, whatever it is that is loading the controls, can provide to them via a property or method the data structure. It could do this after ever time it loads them dynamically. That way the controls will always be given to them the structure they need. Between postbacks of course, you'll have to have a way to save this structure. How best to do that depends on the nature of the document -- if its compact enough, and easy enough to covert to xml, you could convert it to an xml string and store it in ViewState. Or if you have some way of saving it to a database, you could do that too.

    I hope this helps... good luck.

  • I am having problems with a bulk delete I have in a gridview.
    The gridview is nested within a repeater. &nbsp;The gridview has a checkbox for each row and a single &#39;Delete&#39; button. &nbsp;When this button is pressed, it goes to its onclick function where it looks for checked boxes, and initializes a delete.
    This all seems to work fine and dandy, except when two users are working simultaneosly. &nbsp;If user a deletes rows 1,2 and 3, and user B adds 5 rows at the same time, none of the rows are deleted, and the checkboxes continue to be checked. &nbsp;(Although, if one of the 5 rows is inserted and displays between 1 and 2 or 2 and 3, the first 3 rows are checked.) &nbsp;
    I can&#39;t seem to figure out how to delete these rows before ASP.NET checks to see if the gridview has changed.
    Any help would be greatly appreciated.

  • This was a very informing article.

  • Excellent article thanks. Here&#39;s a question though: an alternative to having properties that are directly put into/obtained from ViewState (in get() and set()) is to store the property to a private member variable and explicitly save to/obtain from ViewState in the SaveViewState() and LoadViewState() methods.
    What are the pros and cons of this?

  • Matt -- that works fine, but you have to be careful not to stuff the default value into viewstate when saving -- and, you have to be careful not to overwrite the existing value during load if viewstate for that value is empty. Much easier just to use the statebag directly.

    Basically, just loading your control or page for the first time (!IsPostBack) shouldn't result in any persisted viewstate at all, unless your control or page has loaded dynamic data and plans on letting viewstate maintain it.

  • Great article. &nbsp;I&#39;ve read it a few times in an attempt to hammer these questions into my head. &nbsp;Although sometimes I would like to hammer asp.net
    I&#39;ve run into a strange problem when I create checkboxes dynamically. &nbsp;The checked state of the checkboxes seem to be reloaded fine on the page, but not until after Page_LoadComplete. &nbsp;The checked state always seem to evaluate as false before Page_LoadComplete. &nbsp;Any insight into would be appreciated!

  • John -- are you creating them during the OnLoad phase? If so, thats why. Posted data is processed in two passes -- one before OnLoad, and one after OnLoad. The one after OnLoad is so that controls that are dynamically loaded in OnLoad can still load their posted data. However, that also means their state won't be up to date until the 2nd pass, so basically in your PreRender phase.

    If you can rework your solution so they are dynamically created during OnInit it will solve your problem since they will load their state before OnLoad. If OnInit is too early because you depend on form state, you could do it in LoadViewState -- which is just before form data is processed.

  • I have a question regarding dynamic &quot;Web User Controls&quot; that contain Databound DropDownLists.
    I have one UserControl being loaded dynamically depending on the number of times the user has pressed a button (could add infinite user controls to the page). &nbsp;Now, the above &quot;user control&quot; calls a second &quot;user control&quot; and loads it into a PlaceHolder on the first &quot;user control&quot; depending on the dropdownlist within the first user control. &nbsp;This can happen infinite number of times for each &quot;1st User Control&quot; on the page. &nbsp;The &quot;second user control&quot; has databound DropDownlists in it. &nbsp;
    Now, I have the enableviewstate for all of these controls set to &quot;True&quot;. &nbsp;I know, I know... bad me. &nbsp;But the funny thing is, the &quot;1st user control&quot; keeps its state. &nbsp;The &quot;second user control&quot; does not keep its state on postback, even though viewing the page trace, the viewstate for that particular dropdown control is the correct selectedvalue (it resets itself).

  • Bryan -- I'm not 100% sure I understand the scenario. But it sounds like you must have some way of tracking which controls have been created. Remember that when you add a control dynamically, that control will vanish from the page on the next postback unless you add it back again. So you need to keep track of which selected values the user has clicked on, and then rebuild the list of user controls on postbacks.

  • Bryan,

    So you are navigating through the controls in order to detect dropdown lists, and then writing out their selected value.

    I don't know what problem you are specifically having, but I'll try to help as best I can if you give me more details. Start by sending me mail about the high level goals you have. Its likely you can avoid using dynamic controls altogether, and that greatly simplifies things. Honestly though I'm quite busy lately so I can't promise a speedy response :)

  • Great article! Before I read this article, I was confused by why the value of IsDirty property is always true, and only in a few situation it&#39;s set to be false by SetItemDirty method.
    When deriving from an existing control, you can set any property at any time without it being saved to __VIEWSTATE, as long as you know which StateItem it uses and remember to reset its IsDirty property to false. Here&#39;s a new DateTimeLabel with its Text property set in OnLoad:
    public class DateTimeLabel : Label {
    &nbsp; &nbsp;protected override void OnLoad(EventArgs e) {
    &nbsp; &nbsp; &nbsp; &nbsp;this.Text = DateTime.Now.ToString(&quot;MM/dd/yyyy HH:mm:ss&quot;);
    &nbsp; &nbsp; &nbsp; &nbsp;this.ViewState.SetItemDirty(&quot;Text&quot;, false);
    &nbsp; &nbsp; &nbsp; &nbsp;base.OnLoad(e);
    &nbsp; &nbsp;}
    }

  • Cat -- SetItemDirty is a trick you can use if you must, but in general I wouldn't recommend it. This DateTimeLabel doesn't behave like most controls, and that inconsistency is going to be frustrating for those who use it. Maybe in this situation it would be alright, since it isn't likely a dev would want to set the text property (since its specifically designed to show the date). But if they did, you'd be overwriting the value with your own.

  • First, thanks for the great article. Next, a quick question.
    On August 29th, you state:
    &quot;For example, if a textbox has value &#39;foo&#39;, the page will load with &#39;foo&#39; in the box. If the user changes the value to &#39;bar&#39;, and then before doing another postback a callback occurs, the value posted in the callback data is &#39;foo&#39;. There&#39;s a way to update the data so it represents the current state of the form instead.&quot;
    What is that way to get the latest values when you make a callback instead of postback?
    Thanks.

  • Jack --

    Normally you perform a callback like this:

    WebForm_DoCallback(...);

    To 'update' the form data that is posted so it is up to the minute, you must do this just prior:


    __theFormPostData = "";
    __theFormPostCollection = [];
    WebForm_InitCallback();

  • Nash --

    Why are you storing data in response to TextChanged? Why not just calculate your data when you need it, such as in the button click event? That way it doesn't need to be in viewstate at all, and you don't need postbacks between each textbox.

    Assuming you can't change that design... something else you said concerns me. You have a button that opens a javascript confirm dialog. You seem to be saying that there is a postback occurring _while_ this dialog is open? I'm kind of lost after that -- the dialog is a client-side operation, there shouldn't be anything at all going on server side at that point, not until they user dismisses the dialog.

    Just a shot the dark here, but since you are doing postbacks between each textbox, its quite possible the user is clicking on the button before the last postback is finished. So you'd see the postback of 'C' occuring correctly, but then another postback would come in afterwards, and that postback would not contain the updated viewstate since it was posted from the same form the first one was. If you get rid of the postbacks like I stated in the first paragraph, your form will be much zippier and won't have this problem. Otherwise, you'll have to disable the submit buttons when the postback starts, or the user may click them too quickly.

  • Kmobarra --

    It shouldn't have to matter when you populate the control -- before, or after viewstate is loaded. The fact it does matter kind of indicates a design issue. Instead of populating as soon as the datasource is assigned, why not populate in DataBind() just like other databound controls do? The containing page would set the datasource then call databind -- but it would only do this on !IsPostback. Then in your tree control, you have to rebuild the control tree on LoadViewState. So you will need to save whatever information you need into ViewState at the time DataBind is called to be able to do that.

    That being said, let me make sure I understand the problem. The page is assigning the datasource during page_load, and I presume it is doing that on every request? So your problem is, the page loads with the first set of data -- then the user makes some client side changes and performs a postback. The controls viewstate is loaded and it repopulates itself. Then page_load comes along again and the data is reassigned, causing the control to be repopulated and the values changed by the user are lost. Am I right? Or, perhaps the issue is that the posted values of input controls like textboxes are not updated by page_load (because the controls were added during page_load, they won't get posted values until the 2nd pass a loadpostdata which is after page_load)?

    I still think that rethinking the design a bit like I said in the first paragraph is the right way to go... but a quick workaround for the situation I described is for the page itself to dynamically load the control. This is assuming your issues is with viewstate... it won't help you with the post data. In page_load, you create the control, assign the datasource, and then add it to the control collection (add it to a placeholder more than likely). This lets the page get a chance to assign data to the control before its Init event, since Init won't happen in the control until it is added to the control tree. It's a hack solution though... your control aught to behave like every other databound control. The page that uses it should be able to decide when the data is refreshed and how often.

  • To Everyone -- pretty much 100% of the questions I get about ViewState issues aren't really ViewState problems at all. It usually boils down to a dynamic control issue.

    Just keep this in mind -- if you add a control to the tree dynamically, you must add that control again on the next request, it wont be there automatically. ViewState is responsible for the data in the control, not the existence of the control in the first place.

    But don't confuse that with initializing the control. When you add a control dynamically you should initialize its "initial" values before adding it to the control tree. But the values you give it SHOULD NOT be dynamic! For example... theres a dynamically added label on your page that starts off saying "ABC". A button on the page changes its text to "XYZ" in the click handler. When you initialize the label just before adding it to the tree, you should always set its text to "ABC"! The fact the text was changed is being maintained in the label's internal ViewState -- no reason for you to try and remember it yourself. Rest assured, the label will say "XYZ" if that button was clicked during a previous postback.

  • I take your advice and change the design of the tree control. Thank you.
    Kathy

  • Because disabling viewstate on a control disables it for all its children too, I have changed the property EnableViewState from False to True on the GridView on page Animal.aspx. However the dynamic user child control AnimalPictures.ascx doesn&#39;t persist the viewstate neither. An so, the DataList1_ItemCommand is still not fired.

  • Ruben -- it sounds like theres more going on than you describe. Is the AnimalPictures.ascx the control that contains the Grid View or the other way around? Are you saying viewstate is disabled on the usercontrol as well? You don't necessarily need viewstate enabled to do what you need to do -- itemcommand really has nothing to do with viewstate. Can you provide more details or code samples?

  • Ruben -- you were correct that turning on ViewState for the GridView, because it applies to all children.

    But now that you are utilizing ViewState on the GridView you should not databind it every request. What is happening is the controls are being recreated (automatically for you) when ViewState is loaded, but then you DataBind again, which recreates them all -- and the newly created controls have a different identity (autogenerated ids), so the 'button' you click on isnt the same button.

    Put a !IsPostBack around the databind call, just like you have in the user control, and I don't see why it shouldn't work.

  • Putting a !IsPostBack around the databind call on Animal.aspx.vb doesn’t work. The reason is the following:

    If I use !IsPostBack around the GridView databind call, when the page is posted back, the GridView is persisted thanks to the viewstate is loaded. Until here, everything works property. However, because the GridView is not being re-created (automatically for me) the GridView1_RowDataBound is not fired, and so, I don’t have the opportunity to re-create the dynamic user child control called AnimalPicture.asc when the GridView is populating the first row. Because the dynamic user control is not re-created after postback, the Page_Load event handler on AnimalPictures.ascx.vb is not fired neither. And so, the DataList1_ItemCommand is still not fired.

    If you have another idea, I am ready to test it.


  • ItemCreated is called every request regardless of whether it is being databound or not. That is the correct place to do things like what you are doing.

    Curious -- why not simply declare the user control in the template rather than load it dynamically? Then you wouldn't even need this event. You could even set that HiddenField property on it using the proper Databinding syntax HiddenField=''

  • You said: why not simply declare the user control in the template rather than load it dynamically?

    I don't understand what you mean. Can you explain to me your idea with more details, please?

  • The reason to load the user control dynamically is because I need it only for the first populated row populated on the GridView. If I declare the user control in the template, I think, it is not very efficient to have a user control on each GridViewRow when it is only used once.

  • Ruben -- the user control contains a DataList. I assume the button you are clicking is inside the datalist, no? The DataList will "consume" the click event and fire its own item command event -- and then thats where it stops. If you want it to keep on bubbling up you will have to add code to handle the DataList item command and then raise a Bubble event. Then the GridView will get the Bubble event and raise its ItemCommand.

  • Infinities loop -- Let me recap several things:
    I have created a label control for testing purposes inside the dynamic user control. I have assigned the value &ldquo;Hello world&rdquo; to the label control declaratively. After that, at the end of the Page_Load event handler I have changed the text property value to &ldquo;Happy programming&rdquo; programmatically to start tracking viewstate. When the page is posted back and the execution code is located at the beginning of the Page_Load event handler, I see that the text property value of the label control is &ldquo;Happy programming&rdquo;. That means:
    1. Using GridView_RowCreated as the place to load the dynamic user control and putting a !IsPostBack around the databind call on Animal.aspx.vb has been an improvement in the system. Now the viewstate is persisted inside the dynamic user control. Before, it wasn&rsquo;t.
    2. You were correct and I was wrong. ItemCommand really has nothing to do with viewstate. ItemCommand is still not fired and viewstate is persisted inside the dynamic user control.
    Answering your previous question: Yes, the user control contains a DataList and the LinkButton I am clicking is inside the DataList. You can look at the code I provided to realize about it.
    What is happening now is the following:
    When I click the LinkButton and the page is posted back, the Page_Load event handler inside the dynamic user control is fired. However, when the Page_Load event handler has finished to be executed, the execution code jumps to the detail page about the animal picture clicked on, and the DataList doesn&rsquo;t have the opportunity to &quot;consume&quot; the click event and fire its own item command event. Because of that, the DataList_ItemCommand is not fired inside the dynamic user control and I cannot raise a Bubble event. So, the GridView will not get the Bubble event and raise its ItemCommand.
    Why the DataList_ItemCommand is not executed after finishing Page_Load? I don&#39;t know.

  • Only removing the line !IsPostBack around the databind call on the dynamic user control I can do the DataList1_ItemCommand to be fired. The problem is that I need that line and it shouldn&rsquo;t be removed.

  • Ruben -- Do you still have ViewState enabled on the GridView? If its enabled you should be able to keep !IsPostBack.

    I notice you are using an image inside a linkbutton. Why not just use an ImageButton? It gives you the functionality you want, you can still set a command name and argument, etc.

  • InfinitiesLoop - I have viewstate enabled on the GridView and dynamic user control. Also, I have !IsPostBack around the databind call on the GridView and dynamic user control. The dynamic user control is re-created inside the GridView_RowCreated.
    Yes, you are right. I will change the implementation to use ImageButton instead of an image inside a linkbutton.
    Anyway, I don&#39;t know what to do more to fire the DataList1_ItemCommand.

  • The CLICK (not COMMAND) event should fire on the image button. If it isn't that explains why item command isn't. Does the button still exist after the postback? Are you doing anything else peculiar besides what you've outlined?

    Check this... in the page put a break point in OnLoad, PreRender and in the GridView_ItemCreated event. On the postback where you click on the image button, what happens first, ItemCreated or PreRender?

  • Before posting back the page, the order the events are executed is:
    Page_Load
    GridView1_RowCreated
    Page_PreRender
    After posting back the page, the order is:
    GridView1_RowCreated
    Page_Load
    Page_PreRender (is not fired)
    ImageButton1_Click (is not fired)
    The ImageButton still exists after the post back:
    DataList1.Controls.Count -&gt; 4
    DataList1.Controls(0).ID -&gt; Nothing
    DataList1.Controls.Controls(0).ID -&gt; Nothing
    DataList1.Controls.Controls(1).ID -&gt; ImageButton1

  • There's no way Page Prerender doesn't fire unless there's a redirect occuring or its a callback or atlas partial update. There must be more going on than you've described. Do you want to send me your project? I may not be able to run it without your middle tier or backends but I can still tell a lot more.

  • InfinitiesLoop -- There are several points I would like to comment to you:
    1. After clicking on the ImageButton and the page posting back, why GridView1_RowCreated is executed before Page_Load? Is that the normal flow? I think Page_Load should be always be executed before GridView1_RowCreated. Am I correct?
    2. Why Page_PreRender is so important for you to determine if things go good or wrong? I never use Page_PreRender in my project.
    Thanks

  • Ruben -- (1) No... RowCreated will happen whenever the rows are recreated. That isnt necessarily at a particular point in the lifecycle. It so happens that the rows are recreated immediately after viewstate is loaded, which is before page load. (2) I was only using PreRender as a measure of when the event fires -- certain things are too late if they happen after prerender. No reason to get into the details. You should definitely always get a page_prerender event though, unless again, the postback is a partial update in atlas, a callback, or a redirect or response.end occurs before hand.

  • Great read! Clearly explained.

  • InfinitiesLoop -- Have you received my comments about the Gridview simplified full version? Do you think I found an ASP.NET bug? All my experiments about getting LinkButton_RowCommand to be fired inside a dynamic user control inside a GridView row template were failed.

  • Ruben -- I sent you an email asking for you to attach the files. Perhaps you didn't get the email, or I didn't get your reply. Send me an email through the 'contact' form on this blog, then we can communicate privately instead of through this clunky comment form.

  • Great article! Thanks!

  • I have to disagree with whomever wrote about the humor. Most tech articles are way, way, way too dry. The humor keeps me going.

    Great article, I learned more than I thought I would, thanks for all the effort it took to prepare it.

  • Like all previous commentators I want to give great kudos to this excelent post! At the moment I mess around with some performance issues on a ASP.NET application and found great support in this. So thanks a lot!
    PS: I will mention this post in my German .NET blog for advice-seeking German developers ;-)

  • Wow! what can i say? great article, indeed!

  • In response to a submit button, which is capturing a variable parameter on the page, I am dynamically creating (multiple) xmldatasources and dynamically creating gridviews using the xmldatasources, which have a checkbox item in one of the columns. I am querying multiple distributed databases to build the data, and the number of datasets returned varies, which is why I build the gridviews (and their underlying xmldatasources) dynamically. However, all is lost on a postback. I need to save these dynamically created controls to the viewstate (these are not created onload or oninit, but in response to a submit button ...) When a user presses another button, I need to access the checked records and use information from them, however the gridviews, along with their checked checkboxes, are lost on the postback. Is there an easy way to save the viewstate of the dynamically created gridviews?

  • Gail Lampinen -- congradulations, you're the 100th commenter to this entry :) And happy new year....

    First of all, ViewState of dynamically created controls is saved automatically. The fact the control exists on the page is NOT. There's an important difference there... because the issue you are running into has nothing to do with viewstate at all.

    Second... just because you have a variable number of items to create, doesn't mean you have to do it dynamically. That's what a repeater is for! Why not put your xmldatasource and gridview inside the item template of a repeater? All you would need to do is databind that repeater, and volia... all your gridviews and datasources would be created and automatically maintained by the repeater on your behalf.

    Give it a shot, if you need help working out the markup details, I will need a bit more detail. Contact me through email if you need help.

  • Excellent read. And for the native English speakers, the humor is a breath of fresh air when trying to research & understand frustrating problems. Thanks!

  • I have a dropdown list which I bind on the OnInit page and its view state is turned off.
    The AutoPostBack property of the dropdown list is set to true.
    Am running into a very strange situation:
    When I change the drop down index the SelectedIndexChanged event is fired(not strange at all till now).
    Now if I click on any other button that causes a PostBack on the page the SelectedIndexChanged event is firing as well(very strange).
    Any ideas why this is happening and how could it be avoided?

  • Shad -- First, the event is meant to fire whenever the index changes and theres a postback, not just when autopostback is enabled. The dropdown uses ViewState to remember what the previously selected index was. That is how it knows whether the index has changed. Since you have viewstate off, it will always think the previous index was 0, so it will fire every postback.

    May I ask why you are using the SelectedIndexChanged event? There's probably a different way you can handle it to work around this issue.

  • Thanx for that information. Well on the SelectedIndexchanged event am using the selected value to retrieve some information from the database and display it on the page.
    After what you explained I guess the solution would be to create a custom control derived from the dropdown and override the LoadControlState and SaveControlState events and save the selected value in the ConstrolState of the dropdownlist.
    That way it will always remember the previous selected value which will avoid firing the SelectedIndexChanged on each postback of the page. Still I have to implement it to see if it works!! What do you think?

  • Shad -- that would work, and you'd be able to reuse it for other purposes, so thats a plus. If you were just looking for a quick workaround though, it would be simplier for you to just remember the selected index on the page itself by storing it in viewstate.

    Something like this:

    protected override OnLoad(...) {
    object o = this.ViewState["index"];
    if(o != null) {
    int oldIndex = (int) o;
    if (oldIndex != ddl.SelectedIndex) {
    // changed!
    }
    }
    this.ViewState["index"] = ddl.SelectedIndex;
    }

  • Reynold -- As long as you are loading the controls each request, they should retain their viewstate automatically. The fact they are loaded dynamically does not mean their viewstate is not maintained, it is. There's probably some other issue, unrelated to viewstate. Read the first paragraph of my article on understanding dynamic controls :)

    See if you can boil down the issue into a really simple page and user control or whatever. Get it down to the minimum set of code that still duplicates the problem. Doing that may reveal the problem to you (because you'll remove some code and it will suddenly and mysteriously start working). If not, then you'll have a nice compact "repro" of the problem that you can easily post here or send to me via the contact form.

    Either way, we'll figure it out...

  • Shad --

    Certainly caching the data would work, even if the data is constantly changing within the database. But I'm not so sure thats the best thing to do. Devs tend to be afraid of database access for some reason... sure, its best to minimize the calls to the database if you can, but sometimes an extra call is more appropriate, and I think this may be one of those scenarios. If you cached the query from the first databinding, you'll be retaining all the data in memory "just in case" you need it later. But if you don't need it later, it was a waste. If the typical postback is not due to the dropdownlist changing, then you will be typically retaining data that you don't use. An extra database call might make the request slightly slower for that one user, but the server as a whole is better off.

    That's just how it is on paper though... in reality, it depends on a lot of factors, so I can't say.

  • Thanks for your help. After stripping my app down to the bare minimum, I noticed that the EnableViewState flag for the instance of the user control in the default page was set to false. The obvious things are always the hardest to find and debug! After setting this to true everything works as expected.

  • Great article! (not saying because I am going to ask your help :). It truly is! ). After reading the article which made lots of sense, I realized that I should be locked permanently for view state crime(s) ;-)

    Anyway, started fixing the view state issues. Now I am struck with this problem. The article says that the selected value does not get reset because of disabling the view state but because of the drop down is being bound again. But if I check the selected value in any event handler, it is empty. The drop down is not getting repopulated at this point of time. If I enable view state, the selected value miraculously appears. Am I missing something here?

    I am completely lost :-(

  • Mithu -- if you disable viewstate you need to rebind it every request, are you? If you are, when and how?

  • I am. &nbsp;Rebinding it in page_load of the child control the first time and from the event handler on the parent control when the events get bubbled up from the child control to the parent.
    My child control has a text box, a drop down, and two buttons. I checked the drop down value on click event , it is empty. But the text box has the entered value. &nbsp;I couldnt understand why.

  • mhaemp -- Its better to delegate to child controls if you can. Otherwise you have to worry about the value you store being different than the value in the child control. There are plenty of times where delegating isn't appropriate though, because there may not be a direct relationship between your property and child control properties, in any combination. In those scenarios its best to store it yourself, and then use/consume/dependOn the value of that property as late in the page lifecycle as you can (ideally, Render).

  • Mithu -- I'm still not clear on what is going on. You must assign the DropDown's data source and call DataBind on it every request if you are disabling ViewState. Not in response to an event, not in only certain conditions, but always. Perhaps you can post some code that illustrates your problem? Ideally, boil down the code to the minimum set of code and markup that you can while still illustrating your scenario.

  • I have an user control , say ParentControl in my page. ParentControl contains the search control and some other controls.

    The search control has a drop down, text box and two buttons(search and clear). The drop down value comes from the DB. So I thought of disabling viewstate and bind the drop down every time. Because the only time the page gets posted is when the search or clear button is clicked.

    I disabled view state on the page , ParentControl and SearchControl.

    Parent control contains

    private void Page_Load(object sender, System.EventArgs e)
    {
    if(!IsPostBack)
    {
    -- code retrieve value from DB.set to variable in user controls --
    SearchControl1.BindData();

    }
    }

    private void SearchControl1_Command(object sender, CommandEventArgs e)
    {
    -- code retrieve value from DB.set to variable in user control --
    SearchControl1.BindData();

    }


    SearchControl contains

    private void Page_Load(object sender, System.EventArgs e)
    {
    if(!IsPostBack)
    {
    BindData();

    }
    }
    public void BindData()
    {
    -- code to bind data to drop down, text box --
    }
    private void btnSearch_Command(object sender, CommandEventArgs e)
    {
    -- code to bubble up event --
    }

    If I try to see the value of my drop down and text box in btnSearch_Command, text box still has the value but not the drop down. Why? If I enable view state, I can see the selected value here. I dont know if this is even related to view state.

    I checked the selected value in the client side just before the postback, it is fine.

    I hope all this makes sense.

  • Mithu -- you say you will bind it every request, but then you have:

    if(!IsPostBack)

    That means you are not rebinding the data on postbacks. Since ViewState is disabled, the DropDownList's data will vanish after a postback. You need to call DataBind on it every single request, and you need to do it in OnInit. If you do it in OnLoad, the original problem you quoted me on comes into play, where the selected value is reset each time.

    Please also keep in mind that when you call DataBind on a control, you are also in turn databinding all of that control's child controls. So if you call DataBind on a user control which contains a DropDownList, you have just databound that DropDownList, too. Many people don't realize DataBind is a recursive call, and they end up databinding things multiple times. Sometimes all that causes is slower performance, but sometimes it causes problems.

  • Thanks for the reply Dave!

    I do call the data bind every postback. first time in page load then from the parent control after the event bubbled up all the way to the parent. And the user control is nothing fancy just a text box, drop down and buttons.

    Anyway I couldn't bind the control in Init() , because the pages are designed in such a way to handle all the db calls, the user controls only bind the retrieved data from the page. The child controls Init fires before the parent control and pages, I couldn't bind the drop down in the child control on Init because I don't have the data available to child at that point of time. So I realized my best bet is to enable view state in this case, unless I am missing some other obvious solution.

    I appreciate the help and the article! It gave me a very good understanding of what to do and what not to do with view state.

  • Sabih -- I'll need more details or code samples. It sounds like you have viewstate disabled on the repeater. Keep in mind that disabling viewstate for a control also disables it for all its children, so you could also possibly have viewstate disabled on the control the repeater is in, or it could be disabled for the entire page.

  • Mithu -- "first time in page load then from the parent control after the event bubbled up all the way to the parent". Sorry, I'm still confused :) What if the postback is caused by something other than the bubbled event, like a seperate button on the parent page? You will lose it. You need to call databind every request, from the same code. Why complicate it by splitting it into two places?

    The fact you depend on state info to perform the binding does mean you can't do it from OnInit. That does complicate things. Unless your viewstate on that page is unacceptably large I wouldn't try too hard to work around it, just surrender yourself to it :)

    I say that because its much easier than the solution -- you would have to write a custom control for this scenario, or make the dropdown list a dynamic control. That would allow you to bind it later in the request but still disable viewstate... its just, not worth the effort unless you have a big viewstate problem on that page.

    I can help you with that if you want to persue it, just send me mail through the contact form so we can take it offline.

  • This article provides every information about ViewState.

    Thanks for the same..


  • Great article which clearly explains the fundamentals.

    However, I have a problem with a dynamically loaded user control and viewstate.
    I understand about how and where to dynamically load controls and fast forwarding through events when attached to the control tree (and yes I do need dynamically loaded user controls).

    If my user control contains a dropdown list with viewstate enabled and populated with list items when first created, then I would expect the list contents to be restored on postback after the user control is recreated (without having to reload the list contents). This does not happen and tracking the page/control events indicates that LoadViewState is called ok before the user control is recreated in the page load but is never called after the user control is created and attached to the control tree. This, of course, could have many repercussions for other dynamically created controls.
    I know that creating the user control in OnInit would solve the problem but this is not always possible. Is there a way to 'force' the loading of view state for the user control after the main LoadViewState has been called ?

    Thanks in advance.

  • Andy -- don't worry, it's not a hole in the framework. ViewState is loaded for dynamically created controls in OnLoad, I can assure you of that. You said you only see LoadViewState once, but are you referring to the LoadViewState on the page only? Each control has its own LoadViewState, so you should be looking for it happening within the UserControl.

    If you aren't seeing that either then there's another problem going on. It could be lots of things, like maybe the id of the control is different on the postback. I would need to see some code. Feel free to post code here if you can summarize it tightly enough, or use the contact form to send it to me privately.

  • Hi Dave, what if the postback target is to another page?
    For example PageA.aspx dynamically create a user control, let's say ucC, and I add it in a placeholder plhD (declared), and the postback target of the form is PageB.aspx.
    How PageB.aspx can retrieve the values from ucC, because I can load the user control, but cannot add to the control tree. I use PreviousPage property to access PageA.

    Thanks in advance

  • I was tracking page and control LoadViewState and I could see the page LoadViewState called but not the control LoadViewState for the dynamically loaded control.
    However, I have solved the problem. By placing the user control creation in an override page LoadViewState function after a call to base.LoadViewState(savedState) it all works OK.
    I think the base call allows the page ViewState to be loaded and is, therefore, accessable but the recursive child control LoadViewState is called after the page LoadViewState returns by which time the dynamic controls are created and the ViewState is loaded for all controls.
    protected override void LoadViewState(object savedState)
    {
    &nbsp; &nbsp; &nbsp; &nbsp;base.LoadViewState(savedState);
    &nbsp; &nbsp; &nbsp; &nbsp;SetupDynamicControls(); &nbsp;// which can use page viewstate
    }

  • Andy -- viewstate for dynamically loaded child controls will be loaded even after Page LoadViewState. That plays into the "catching up" with the event cycle feature. Its a primary scenario that ASP.NET expects, so if it's not working there must be something else wrong.

    Setup a small test environment (with a completely new project, to avoid outside influence). Try to duplicate your problem by creating a page and control that does nothing but override LoadViewState. Put some text in it too so at least you know its loading.

  • ChRoss -- thats a great question! Its great because I've actually never even tried that scenario before.

    The value is null probably because the page doesn't exactly go through its typical processing. But it is a page instance, so you should be able to find the control using FindControl.

    You should have access to the placeholder you mentioned... call FindControl('id') on it, where 'id' is the id you give to the UserControl you dynamically loaded. It would work assuming the PreviousPage goes through the life cycle up to OnLoad, which I honestly have no idea about. So I'd love to hear how it goes.

  • how to get the view state value in page load? could you please help me?

  • Hmmm... I made a further test.
    My user control contains a textbox txtC
    Case 1
    In PageA.aspx, I have textbox txtA, and also a user control created dynamically on the page load. When submit to PageB.aspx, I can retrieve both textboxes value (txtA and txtC), so all working fine.
    Case2
    In PageA.aspx, I have textbox txtA and a button. When this button is clicked, I create the user control. When click another button to submit to PageB.aspx, I cannot find the user control (using FindControl). it shows null. I check on the placeholder containing the user control, placeholder.Controls.Count return 0.
    So, only if the user control dynamically created after postback, then postback to another page, I cannot retrieve the value.
    I&#39;m not sure about the life cycle of the PreviousPage, but how do I &quot;load&quot; again the user control? to retrieve the value.

  • Wow I could start a whole 'nother blog just from the comments to this one entry...

    Anyway :) Keep them coming people. One of these days I plan to revamp this article and create a sort of FAQ based on all the comments and questions posted here. My ambition is probably bigger than my will, though.. thats a huge task!

    ChRoss -- controls have to be loaded every request for them to continue to exist. If you only create a control when a button is clicked, it's not going to exist on requests where the button was not clicked, and that includes cross page postbacks. What you'll have to do is when you load the user control (in response to the button click), store something in ViewState (with this.ViewState["foo"] = "bar"). The thing you store is for your benefit, because you're now going to override LoadViewState. After calling base, you check for that same viewstate value, and if it exists, and using any context information you may have stored in it, you now recreate the usercontrol. One more thing though -- if the user happens to have been clicking the button during this request, you'd end up loading it a 2nd time. So in response to the button click, you first clear the control collection of the placeholder you are adding it to. That or you find it and remove it -- or you hold on to the instance you created from LoadViewState and use that to remove it. Doesn't matter how, just get it out of there. And finally -- you'll want the IDs of the removed control and the new control to be the same, so don't allow the framework to auto-assign an ID -- give it a specific ID yourself.

  • :) Yes it works! Thanks a lot!

    This is my snippet of PageA.aspx:

    protected void Page_Load(object sender, EventArgs e)
    {
    if (ViewState["plhAControl"] != null)
    {
    plhA.Controls.Clear();
    myucC = (ucC)LoadControl("~/ucC.ascx");
    myucC.ID = "myucC";
    plhA.Controls.Add(myucC);
    }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
    plhA.Controls.Clear();
    myucC = (ucC)LoadControl("~/ucC.ascx");
    myucC.ID = "myucC";
    ViewState["plhAControl"] = "on";
    plhA.Controls.Add(myucC);
    }

  • Great article. I would like to reiterate a comment left earlier:

    It would be useful if you could extend the article to clarify how viewstate is associated with event handlers e.g. the dropdownlist control's SelectedIndexChanged event handler.

    Thanks,
    Scott

  • THis is a Great Article. I Have one Question though regarding MultiView Control and ViewState.

    I have Multiple User control one per view IN MultiView. If i swicth between Views Those Views are Bind (Say i have a Repeater) and shown. Now When i switch back View A from Visible to Non Visible Mode ItemCreated Event is called for Repeater Even though that View is Not Visible.I want ItemCreated to be called in PostBack Only When View IS Visisble . Problem is If it keeps on calling ItemCreated It is a Performance Bolleneck If i Have Lot OF Views in mUltiView on Server side. IN The ItemCretaed Event I Create Dynamic COntrols back for PostBack If DataItem==Null.

    How To Avoid Other Views not to do anythng when they are Not Visible??? PLease Answer I am IN Trouble...

  • Verinder -- You could load the user control which is in the multiview dynamically. You'd only load the user control which should be visible.

  • Darren -- are you giving each user control a unique ID that is always the same? You could assign an ID which is based on the view it is visible in, for example. UC1, UC2, etc. That way at least the ID of the first control and the 2nd control are different.

    Now, I'm not exactly sure how asp.net 2.0 handles this scenario. It could be that viewstate is loaded by index, in which case having a different ID won't matter. But if not, then it would. Even if it does load by index I believe there's a way to set it back into loading by ID.

    Another solution would be to always load the user control that was visible on the last request. If the selected index has changed, then you then remove the control and load the right one. That may sound like a hack, but I would recommend that approach if you must load them dynamically. Controls just were not designed to be stripped out of the lifecycle mid way like that. By loading the old control first, its viewstate is loaded, and the 2nd control is going to get a fresh start just as if it were a new page request.

    If you don't have many views, you could also always load them ALL every request. Then you just make them visible/invisible based on the selected index. That has the advantage of them being able to maintain state. If someone switches from Tab A to Tab B and then back to Tab A again, all the controls on Tab A will still have all the data they did before. A definite plus if it contains form data that the user may have typed things into.

  • Hi,

    First of loading the control Dyanmically is not a good solution.I Did that but does require lot of work to make it work. It defeats the perpuse of Wizard or Multiview, Then i can write Multiple pages to escape from that coding. If i have a Wizard With lot of steps and Controls are Bidded as you Go from one Step to other. Suppose i moved from Step 1 to step 5. Now at Step 5 Wizard will have a perfromace hit because ItemCreated Event of all step 1-4 even though i am o Step 5. I don't know even what is the use of calling Page_Load of each step in Wizar or Multiview When Only One Control is Visible. Looks like a Flaw in Microsoft design.

    PLease tell me some elegant solution without Dynamic controls.

    Verinder

  • Verinder -- and what if the user is on Step 5 but needs to go back to Step 1?

    The fact all the controls continue to exist is by design, because it allows them to (1) continue to maintain their state, and (2) you can access them when the wizzard is finished in order to process the information. Controls in general can't just assume they are not going to be visible either, since it is quite possible that you (user code) may make them visible at almost any time. Even so like I said, data in invisible controls is still accessible, and thats a good thing. Visible=false doesnt mean "this control does not exist", it means it isn't rendered into the html, nothing more!

    Since you seem not to need the control anymore you must be using the data as soon as they move to the next step -- why? Gather it all at once when they are finished, it would be simpler. If there's reason why you need to do it the way you are, rather than try to remove the control or something you could always just clear the bound data from them, so there are no items to create (controls.Clear, or re-bind it with no datasource).

    You are worried about 5 controls going through ItemCreated events? Surely there are more important bottlenecks in your app. A complex asp.net page can have hundreds upon hundreds of controls on it and still perform extremely well, so if thats your only bottle neck you're in good shape. Sorry, it just seems like you're worried about the wrong thing.

    The design of the framework may not fit 100% your scenario here, but thats how frameworks are. They meet a great many needs and to some degree allow customization for specific scenarios.

  • Great Article...
    I just found my real job position &quot;would-be shoddy asp.net developer&quot; :P
    This has open my mind.
    I&#39;m going to code better after this.
    Thx a lot
    P.S. how did you know I used to be an VB developer, ah? LOL

  • You are right that ItemCreated Event doesn&#39;t cause much of time.. But What i have seen is ViewState of Page Keeps Growing as you Move from one step to other . It contains the ViewState of all the COntrols in each Wizard step once they are bound. So It does increase the Size of page passing through the Wire even though the UI which you are seeing in the step is very simple. I was able to get round this probelm by Enabling the ViewState of View Which i am going to show using StepINdexChanged Event. That Solves the problem.
    Thanks a lot!! &nbsp; My Manager was very worried about having multiviews and Wizards inside multiview can cause the page to slow down. Based on what you said.. I removed all the code from Page_load and Bind the UI which i am going to see on StepINdexChanged Event of Wizard . Along with that i set the ViewState of all Views set to False other then what i am going to show. &nbsp;That Solves most of the Issue..
    My COmpany is very worried about using 10-15 views in one page with each view has its own user control. Based on your opinion i will go ahead and push this Wizard design forward. Other school of though is why can&#39;t we do seperate pages and write Wizard like functionality using page logic. My though was well then what is the use of Wizard if we can&#39;t use that.
    Thanks a lot!
    Verinder

  • Thanks a lot!.. I did see that ItemCreated Event is not very heavy processing wise. What i have noticed is ViewState of page keeps growing and it adds the viewstate of each control on the page as you move step forward, and hence will be heavy on wire even if the view which is showing up uses 10% of hidden field which is out there. &nbsp;I Used EnableViewState of WizardStep to set the ViewState f step i am going to be in and disable all others. THis clears that issue.
    I will try Controls.Clear solution also. &nbsp;
    My Company(Managers) were very concern about 10-15 controls in one page and all doing heavy lifing work. I solved the probelm by removing everything from there Page_load and Call Binding when we go to that step. Also Using ObjectDataSource Declerative DataBinding DataBinding is called by itself when view shows up.
    ViewState and ItemCreated solution i resolved by creating WizardBase which Captures StepINdexChanged Event to disable all view state other then active step.
    Thanks for telling me that it won&#39;t be performance issue because we were thinking to write seperate pages to mimic Wizard.
    Thanks
    Verinder
    Thanks
    Verinder

  • Excellent article. Thanks for taking the time to put it together. I found the article while looking to solutions for a problem that I have.

    I want to use an editable grid control on a page. The grid rows will be based on the selection in a drop-down. When the page first loads, the drop-down will have a default value, and the grid will be populated based on the default value.

    If the user selects another value in the drop-down, I want the grid rows to reload (via callback), taking the user's selection into account (basically rebuilding the grid with a new DataSet). When the user presses the "save" button on the page, how can I get the data to save to the correct new dataset?

    I'm not sure if this ViewState article is the right place to ask this question, but any help you could give me would be awesome.

    Thanks again for the excellent article!

  • kurt - sounds like you want a two-way binding, which you can do pretty easily with a datasource control. You can even make it work against a custom business layer using the object datasource control. This definitely isn't my strongest area :) But there should be lots of examples out there. Sorry I'm not more helpful than that.

  • Kurt--I have Done the same thing with ObjectDataSource and With Two way dataBinding . What you need to do is in Button Type CommandName="Update" and Use Two way dataBinding with ObjectDataSource. I have done this with FOrmView not with DataGrid though but concept is same

  • Excellent article. After 3 years with ASP.NET I finally get what ViewState is REALLY about.

    I do have a question though.
    I have a UserControl with a property ClassificationName that uses ViewState as the backing. I also have a DropDownList that uses the ClassificationName as a parameter when DataBinding. DataBinding occurs through a Click event handler that sets the ClassificationName property then DataBinds the DropDownList.
    I'd like to avoid having the DropDownList writing its contents into ViewState, I would prefer to DataBind the list BEFORE ViewState tracking on the DropDownList kicks in on subsequent requests after the Click event handler has been called.
    The obvious problem is that I don't have access to my ClassificationName property until after the Init phase on the UserControl by which time its too late to do this.
    Is there an elegent way to achieve this? My best guess is that I need to defer initialisation of the DropDownList control by dynamically adding it to the page after the Init phase is complete and I have access to the ClassificationName property.

    Any thoughts would be appreciated.


  • Graeme -- yes, you are right that you need to delay initialization of the dropdown by creating it dynamically. I wish there were a non-dynamic way of doing it, but its your best bet.

    What you should do is use a viewstate key to store the classification name which you have databound. Then in LoadViewState, after calling base.LoadViewState, you check for that key and if it exists, you create the dropdown, bind it, and add it to the page.

    Then, its possible the click event comes through again later on in the request. So you would have to be sure to remove the old dropdown and create a new one. Give each a specific ID that is the same every request, or make the ID based on the classification name. It should work like a charm.

  • You've spelt "its" wrong in the caption of the star trek ship.

    It should be "to its own"

  • mehmetserif -- Can you post some code?

  • Sure

    This is the property that i made to count the button clicks and it'll create fileuploads at run-time according to its click numbers

    public int ButtonClick
    {
    get
    {
    return (int)ViewState["ButtonClick"];
    }
    set
    {
    ViewState["ButtonClick"] = value;
    }
    }

    and then i create the fileupload controls at run-time

    protected void lnkEkle_Click(object sender, EventArgs e)
    {
    ++ButtonClick;
    for (int i = 0; i < ButtonClick; i++)
    {
    FileUpload myControl = new FileUpload();
    myControl.ID = "upload_" + ButtonClick.ToString();
    this.panel1.Controls.Add(myControl);
    }
    lblSonuc.Visible = true;
    }

    then when i want to upload files by those auto-created fileupload controls i get an nullReferenceException

    protected void Button1_Click(object sender, EventArgs e)
    {
    for (int i = 1; i <= ButtonClick; i++)
    {
    myUpload = ((FileUpload)pnlUpload.FindControl("upload_" + i.ToString()));
    if (myUpload.HasFile)
    {
    upload(myUpload.PostedFile.FileName);
    lblSonuc.Text = "basari";
    }
    }

    }

    So i don't know what to do?

  • mehmetserif -- the problem is you are only creating the fileupload controls when the user clicks on the button to add one. If they click on any other button you do not create them, therefore they do not exist. You should read my articles on understanding dynamic controls.

    To see what I mean about them not existing, add another button to your page that doesn't do anything. Add some upload controls a few times, then click that button. They will vanish. Controls created dynamically must be added every request, and you're only doing it as long as they click the add button. You will need to override LoadViewState and create them there. The 'add' button then will just add a single control as well as increment the counter.

  • Masonator -- ImageButtons use a part of page viewstate to register themselves as postback controls. Unfortunately there's no way to turn that off. The reason it needs to do that is hard to explain in a comment... its basically because the name of the posted value coming from the control in the form fields isn't the same as its ID, so it tells asp.net to raise its postback event anyway. The only way around this I'm afraid would be to write your own image control that doesn't need to do this.

    You shouldn't see the same thing for checkboxes, except perhaps if you are hooking into the check changed event.

  • Thanks for the help!
    Imagebuttons arent so much the problem as checkboxes. If you try the code above but add a checkbox rather than an imagebutton, the viewstate still grows.
    The most annoying thing is that im fairly sure viewstate isnt even needed for the checkchanged event to work, as i have managed to get this to fire correctly even when manually setting the viewstate to the empty string. But then, of course, all the imagebuttons on the page stop working.
    Any ideas?

  • CheckChanged may fire without viewstate, but it won't work the way you think. It will only fire if the state isn't the declared value. If you hit it, then switch it back again, the changed event won't fire because its the same as the original value. The checkbox will save its value in viewstate automatically if you subscribe to the check changed event (unless its disabled). Are you using that event?

    If so consider changing your design not to require the event. Usually it isn't necessary -- why do you need to know when it CHANGES? Usually just knowing what it IS is enough. In all my years I've never needed that event...

  • Ahhh, yum!

    The checkbox knows whether anyone is hooked into the event, so just not hooking it should prevent your viewstate growth. If that's not what you are seeing then grab a viewstate decoder and see what the difference is with and without a checkbox on the form.

  • Ok...I think im beginning to understand the situation.

    The viewstate decoder tells me that every listitem I add in the checkbox list is being added to an array in controlstate called "__ControlsRequirePostBackKey__" and this is whats causing viewstate to grow.

    Do you know how I can stop this happening? From what ive read so far, im coming to the conclusion that its impossible to prevent this information being recorded even though, in my situation, its unnecessary.

    Any thoughts?

    Thanks

  • Ok... I hadn't realized this (thank you). CheckBox calls Page.RegisterRequiresPostback, which puts it into that collection. I'm afraid there's nothing you can do about that. One thing that could help reduce the viewstate size in this case though is to make your IDs short. If you have a repeater inside a datagrid inside a gridview and inside that is a checkbox list, then well the naming container'd IDs get pretty long. Keeping the ids 2 or 3 characters long could have a big impact.

    I don't know precisely why CheckBox calls that register method. It may have other purposes, but the purpose I know about for calling that method is when the post data key your control posts doesn't match its unique ID. For example and image button with id 'img1', when clicked on, will post to the server two keys, img1.x and im1.y (representing the x/y coordinates of where in the image you clicked on). Since asp.net can't find a control with that ID it doesn't call its LoadPostData method. But if the control registered that it requires postback, it does.

    Checkboxes use their uniqueID as the name which is posted so I don't see why they need to do that. There's probably some scenario I'm not thinking about. I'll dig deeper and see what I can find out.

    You could also consider writing your own checkbox control that doesn't do that and see what you get.

  • Thanks for the comment.

    I think I understand the situation now and am just as confused as you as to why it requires this information.

    Seems crazy that you have no option to turn it off, either.

  • Great article, thanks for the effort.
    Would you consider expanding this article with Ajax.net and viewstate relation?
    We have relatively large viewstate traffic thanks to our &quot;all inclusive&quot; monster grids. Apart from ones with checkbox column which force us to iterate in entire grid, I guess it will be posible to get rid of grid viewstates all togather.
    cheers.

  • Sorry for being redundant but this is a great article! I read it again and again and today AGAIN and I find new things everyday in it.
    This should be the top thing in MSDN related to ViewState.

  • Hi,
    Iam having a AddNew Button which shows a panel with following controls with a ddl1,ddl2, a textbox and a save button. When i click on Addnew I populate the ddl1 with values and based on a session variable i get the selectedvalue of the ddl1 ( which i set in PAge_Prerender using ddl1.selectedvalue=_value ) and populate the ddl2 based on the selectedvalue.
    &nbsp; &nbsp; &nbsp; The page is displayed fine. The user selects a value from ddl2 , enters some value in the textbox and click on Save button.
    &nbsp; &nbsp; &nbsp; At this point it calls the SelectedIndexChanged event for the ddl1 which causes the selected value of ddl2 to go away. So My Save_Click event fails at it is unable to get the Selectedvalue of ddl2.
    &nbsp; &nbsp; &nbsp; Iam wondering why the SelectedIndexChanged event is fired.
    Also one more thing, the same code works fine in asp.net 1.1 and doesnot work in asp.net 2.0
    I have compared the aspx and the .cs files of old and new ( converted ) sources but donot find anything changed with respect to the ddl.
    Thanks in Advance for your help
    Sada

  • This article blow my mind, just what i needed to definetily understand how to better use dynamic controls !

  • Hello, good and amazing article. I have one problem. I have one composite control with one dropdownlist. The control has a property Enabled, she sets Mybase.Enabled to True or False. If Enabled is true, the dropdownlist saves her value correctly on a Postback, but if Enabled is false, the value is lost. Do u know what can the reason be?

    Than you and greetings from Spain

  • rspaz16 -- do you mind providing a small sample showing the problem? I don't think disabled controls post their value because the browser doesn't include them in the postback data. But even so, I think the DD should still restore its last value from ViewState.

  • Sada -- sorry for the long delay in a reply. Doesn't sound like the event should be firing for your scenario, so there must be something in particular about the code causing it. Do you mind sending me some sample code?

  • Excellent detailing.
    Humour!!!
    I liked this part...in Persisting Cheap Data.
    When you said for lot of unnecessay data stored in viewstate which can be done alternatively also...
    'I often wonder what it would be like if I explained to my grandmother the reason why her internet is so slow is because her computer is telling the server what all the US States are.'

  • InfinitiesLoop, great article unfortunately for me it now means I have a motivation to fix all of the problems it has shined a light on with the way I have done things with a current application.

    If you ever get the chance it would be useful to read an article specific to the GridView and ViewState.

    It would be useful to know what is required to have a GridView with ViewState disabled, that is bound to a datasource (in my case entityspaces) but still allow for extraction of datakeys, sorting, paging etc.

    Also to throw a spanner in, the GridView is part of a custom control, which means no access to the preinit event...

  • Great Article! A lot of ASP.NET programers come from a windows programming background and fail to understand the lifecycle of an ASP.NET page. This should be a must read for all ASP.NET programmers.

  • I especially like your quip about the browser telling the server what the US states are. The problem with simply binding on every init is this: Many times we have to rebind to allow postback events to be raised from dynamic controls. After the event is raised, its even more common to bind yet again to reflect changes or leave the page entirely. Either way, its a waste of a database trip when you could have just examined the form collection to begin with. This is the fundamental flaw of ASP.NET: event-ignorant pages.

    Fun writeup. Well done.

  • You mention that we can hook into the Init event of a static control to dynamically set its properties. Such as:



    However, I'm having problems writing the event handler. The key issue being that the sender object is not initialized so I can't do anything with it!

    public void MyObject_OnInit(object sender, EventArgs e)
    {
    ((MyObjectType)sender).SomeProperty = "foo";
    }

    In the above example, "sender" is null. Can you please provide a code example on how to do this? Thanks!

  • Daniel -- works for me. Sender is the control. Perhaps its caused by something else on the page -- are you using a master page? Can you duplicate this with just a simple page with nothing else on it?

  • And Awesome blog on viewstate

  • Abey -- you say you dont get the values you want when you call A() on the newly loaded user control. But when exactly are you calling it. You make it sound like you're calling it right after loading it, but then the user hasn't had a chance to enter anything yet.

    A control created after LoadViewState will still load its viewstate, so whoever told you that is wrong :) There's no reason this shouldn't work, if it's done the right way. The main thing would be to make sure you're always loading the control that previously was loaded, and the best place to do that would be from LoadViewState. If you follow the pattern I describe in Part 4 of my article on understanding dynamic controls it should work.

  • H Canberger --

    I have thought the exact same thing in the past. But there is one scenario where it's important to store the value even though it is the default. Imagine you have:



    Visible is true by default. Since this is just the declared value, it won't be saved into __VIEWSTATE. Now dynamically set Visible to true.

    foo.Visible = true;

    If the Visible property said hey, thats my default value, so just remove the viewstate entry, then what do you think would happen on the next postback?



    Sets it to false... and then since there's no entry in the dirty ViewState for it, it stays false.

    So its important to store the value even if its the default, because it also tracks changes from the natural, declared state of the control.

  • Thanks for your comments. I knew the pattern was to good to be true. :)

  • Thanks the auther for this great article! It is one of the most helpfull I've ever read. It helped me a lot.

  • Rob -- this is not an issue with retaining ViewState. When you databaind a repeater, you're telling it to start fresh. It throws away everything and binds the new UI to the data in the datasource.

    If you want to save what was changed in the repeater's items you'll have to get them out and put that data into the datasource you're binding to, then add your new item and rebind it.

  • Hi, great articel but I still need some help.

    Using the designer I created a Page that contains a GridView databinded to an XMLDataSource. One of the GridView columns is an TemplateItem containing a dropDownList binded to an ObjectDataSource. The selectedValue of the dropdownlist is binded to the value of one of the gridview's columns. All of this is done by the at design time.

    I encountered some problems:

    1. While ViewState was enabled my page has loaded with a very very big _VIEWSTATE attribute even before tuched any of the controls.

    2. To avoid this and as I have no real need for the viewstate I have disabled it on both GridView and dropDownList and both of the DataSources. But than encountered an Exception on my first page postback. The exception was caused by an empty XmlDataSource, and seemed to happen before reloading the page. I temporerly solved that by assigning an event handler for GridView_Init and inside it assigning the XML to the DataSource. (but this solution causes the pulling of this xml from the server excessively).

    3. Both before and after disabling the viewstate I had problems preserving the dropdownlist selected value after posting.

    I hope I was clear about what I have done and what are my problems, and hope even mroe, that you can shed some light on my issues and help me solve them.

  • Great article, helped in gaining a lot new. Thanks

  • Rony -- without viewstate, the grid is going to re-bind on every request. That means for sure the datasource needs to be available every request. One way or another, the grid needs to repopulate, either from viewstate or from the data itself.

    Also the fact it will rebind on every request means the dropdown is rebinding, too. Rebinding means losing the existing user state, such as dropdownlist selected index or textbox values. The trick is to rebind before these controls load the user state (the postback data), by doing it from OnInit. So you'd just call GV.DataBind() from OnInit rather than allowing the GV to bind itself automatically.

  • Jatin -- an excellent question. One the deserves its own blog entry, I'd say! Check it out! Thanks for the idea for a post.

    http://weblogs.asp.net/infinitiesloop/archive/2007/10/25/understanding-what-page-registerrequirespostback-does.aspx

  • Hi all,
    I have the Attachement.Ascx control in the Mail.Aspx page,
    Which is Loaded in PlaceHolder on the Page_Load, which is in the Formview
    In Attachement.Ascx i have the ListBox were I am adding the Items to the listBox on the button click,

    for the firstTime the item is added it is visible in the listBox but when I click the Button to add the secound Item into the ListBox the firstadded item is lost on, OnPostBack.
    I have tried with True/False for EnableViewState,
    On every Post back the listBox items is Null.




  • I am investigating a performance nightmare we are having and I think it could have something to do with viewstate. We were getting alot of viewstate errors and the coders have gotten those to stop, but our performance is dismal. We spent the last month optimizing our code for SQL, but it's made no change in performance. Your viewstate madness graphic matches our source view EXACTLY. Nutty looking cat upchuck of characters. I am not a coder (many years designing though and good knowledge) but I have spent a TON of money (measured in gold bullion) on trying to figure out the performance problem. The db has 400K records, but we have broken things into smaller tables. Nothing seems to help. I am not real sure the coder knows some of these advanced/proper uses of viewstate for instance.

    Looking at our view source of one of our sites, www.sarasotaguide.tv I am not sure if you can tell if viewstate is our problem, but after reading this article it smells like it?

    Thanks for the great article. I have passed it along trying to give us a better understanding.

  • Dave -- the viewstate size on your main page is about 25kb. Thats pretty big, but it's not so big that you'd have a "nightmare".

    What I noticed though was that your page took like 4 minutes to finally come through. And the size of the HTML of the front page is about 160kb. Thats huge and sure to drive dial-up users away. Interesting the bulk of the size of your HTML seems to be that tree view on the left. You're obviously using Telerik Rad Controls. Those controls are great but their richness comes with a cost.

    Still all of that doesnt explain why it took 4 minutes to respond. To figure that out it would take some debugging. Sounds like the server is doing much more than it needs to, like executing a lot of SQL queries where it could cache the results or consolidate them into one query. Some SQL Profiling would help with that. Send me a private mail and we can dig deeper.

  • Hello,

    I know that it is possible to rebind a dropdownlist on every request in the Init event and the ddl gets the selected index. But I have the problem that this does'nt work in the ASP:Wizard Control - Why?

    I have only a problem with some big (130 rows) dropdownlist resulting in a large viewstate - all other works fine. I only want to "remember" the last selectedindex.

    regards

  • Robert -- are you sure nothing else is re-binding it later on? Remember that databinding is recursive -- if the DDL is within the Wizard and something calls DataBind on the wizard, it's binding the DLL too.

  • Whats all this "you've been kicked in the knee (thats a good thing?)" Good article.

  • Adam -- That's "dotnetkicks". Basically a social bookmarking site for .net

  • This is fantastic - I was getting tidied in knots trying to create a dynamic multiview &amp; you have saved me hours &nbsp;- I'm off to the beach now!

  • InfinitiesLoop can you recomend any articles on getting a GridView to work without ViewState enabled? By work I mean, Paging, Sorting, Editing and Selecting rows... to complicate matters, the GridView is embedded in a custom control and most respond to events on another control.

    The example I am working on is with my page being split into a Master/Detail format. The Master section contains a custom control that has fields in a form layout. The detail section contains an AJAX tab control, with each tab containing a custom control in the form of a list, using a GridView and here is where my hell began...

  • Infinity -

    Thanks for the article. I want to set some Control attributes that are basically static. I do not want these properties tracked by ViewState because that would be a huge waste. So, I do something like:

    protected override void OnPreInit( EventArgs e )
    {
    base.PreInit(e);
    userName.Attributes["onfocus"] = "getHelp('userName','Help1')";
    email.Attributes["onfocus"] = "getHelp('email','Help1')";
    ...
    }

    This doesn't work, .net complains since userName is null. MasterPages seem to be blameworthy. However, it works if I do something like this:

    protected override void OnPreInit( EventArgs e )
    {
    MasterPage master = Master;
    base.PreInit(e);
    userName.Attributes["onfocus"] = "getHelp('userName','Help1')";
    email.Attributes["onfocus"] = "getHelp('email','Help1')";
    ...
    }

    Seems that Master.get somehow makes everything initialized. I'm assuming that it somehow forces construction of the MasterPage object and reshuffles the controls/contentholders.

    So: What should I do. Referencing this.Master on all my my pages in preinit seems like a hack. The only other option I can think of is to perform this option in Render() before calling base.Render(). I suppose a good option would be to share a subclass of Page that has an OnRender() stub.

    Any Ideas?

  • Paul -- indeed I have seen that Master Page problem. I'm afraid that's just how it is, OnPreInit as far as I know was only intended for dynamically setting the master page (one reason why it isn't a control event).

    But actually I would probably do it in Render like you suggest anyway. That way the data can be up to date if something during the processing of the form needs to change it. Render is safe as far as viewstate goes obviously since its after its already been saved with SaveViewState.

  • Thanks infinity,

    I want all of my "life cycle handlers" to look consistent, therefore, I did the following. Hopefully this helps someone later on.

    class MyPage {
    ..
    protected override void Render( HtmlTextWriter w )
    {

    base.Render(w);
    }

    protected virtual void OnRender( )
    {
    }
    ..
    }

    I don't actually name it "MyPage", but this is the base class of all my pages. If you are inheriting from Page and not a subclass, then I recommend refactoring since alot can be accomplished at this level.

    My subclasses, then, look like:

    class AwesomePage {
    ...
    protected override void OnRender( )
    {
    userName.Attributes["onfocus"] = "getHelp('userName','Help1')";
    email.Attributes["onfocus"] = "getHelp('email','Help1')";

    base.OnRender() // Not necessary, but good habit
    }

    protected override void OnInit( EventArgs e )
    {
    ...
    }

    ...
    }


    Now, I just need to figure out why my password-mode textbox's value is not being persisted through multiple postbacks. I have a MultiView and I want to hold onto a password entered on the first view. I have ViewState enabled. It is odd how ViewState acts one way with some controls, and another way with other controls (MasterPages, PasswordMode TextBoxes)

  • In password mode TextBox does not remember the password on purpose. Whether you like it or not, that's just how it was written. I think thats a fair feature though, you wouldnt normally want that password to hang around and have to be cleared manually.

    If you look at its implementation of AddAttributesToRender you'll see what I mean. I suppose you can just derive from it, override AddAttributesToRender, and make sure the Value attribute is added. ViewState still remembers the value of course, but since the TB is empty after 1 post, the 2nd post clears it out, even in ViewState (just as if the user cleared it themselves).

  • Hum, I guess I will just hold on to the password in session state and clear it out after submitting the form. Thanks.

  • Paul -- dont use session state, just use viewstate.

    ViewState["Password"] = txtPassword.Text;

    But even that isn't needed if you implement what I said with AddAttributesToRender.

  • [MCTS Self-paced training kit (Exam 70-528), Microsoft Press, Page 501

    As you might have already noticed, if a user clicks a button to submit an ASP.NET page, the page retains all its values and settings. For example, if you modify the text on a label and the user clicks a button, the modified text is still displayed when the page reappears. This happens because ASP.NET has a client-side state management technique built in: ViewState.
    ]

    So this is totally incorrect statement? Thanks.


  • Raoul -- no thats completely correct. Why do you think not?

  • Thanks for coming back. Your statement at the beginning of the article [Then there's this W3Schools article on ViewState that seems to indicate that posted form values are maintained via ViewState, but that's not true.]

    seems to contradict

    [MCTS Self-paced training kit (Exam 70-528), Microsoft Press, Page 501 - the page retains all its values and settings. This happens because ASP.NET has a client-side state management technique built in: ViewState]

    ?





  • Raoul -- you're painting a broad brush. Both statements are true. ViewState is only one way controls maintain values across postbacks. Regular good ole HTML FORMS play a role, too. For example, disable viewstate on a textbox, and it will still maintain its value, because it is POSTING the value with the form. Make that TextBox invisible then do a post, and the value is lost. Thats where ViewState helps, which would allow it to maintain the value even if its invisible.

  • Hi, thanks for this article. It's really great.

    I'm just new to ASP.NET, learning everything I can. I used to write in PHP. The more I read about Viewstate, I'm getting just one thing on my mind: don't use it, remove completely. It creates a lot of issues / problems. It throws tons of data to the user and back. But this is not that bad, when used properly. The worst thing is that it makes your server application depend on some encoded / hidden data being sent by user.

    I find it unacceptable for a client / server architecture application to depend on the client to work properly. I think it's unsecure by design, no matter how many compensating controls we put on it, it's unreliable, and it's throwing a lot of overhead for nothing.

    To me any application that depends on keeping configuration data on client-side is, sorry for the word, lame. I believe that every data should be repopulated on server-side on every client request. If it's from a database query or an internal application cache, it doesn't matter - it's just a matter of how much code would you write for sake of performance and database profiling.

    Some really expensive to get data can be cached either in session (when they're per-user by nature) or in some application-wide cache (when they're global), but NOT sent to user and asked to be sent back. I really don't understand why Microsoft is forcing this faulty method.

    If I'm just wrong with some basic stuff and reading the whole thing from the wrong side, please correct me. But it doesn't make any sense to me.

    Plus, I'm a bit shocked by the lack of understanding of client/server architecture in some of the developers commenting here. To me, always, a developer was a master of the technology he was using - he had not only to use it, he was supposed to tell it what to do. And here I find people who are devleopers just because they can click some fancy controls in IDE.

    I just hope they won't be writing my next-gen car computer software ;)

  • Jakub -- Thanks for your comments.

    As a rule in a lot of ways I agree with you -- its far better to repopulate data on every request than to have it stored on the client.

    But...

    Storing data on the client... that is not what ViewState is all about. That is what it does, but what data you put there is up to you, if you use it correctly.

    Take forinstance an accordian control, common to many menu systems. You click a category and it expands to show a sub-menu. Ok, now over on the other side of the page you type in your email address and click submit in order to add yourself to the site's monthly newsletter. Oops... now the accordian has collapsed again. Thats not what the user wanted. Better if that menu could have remained in the same state. That is the kind of thing ViewState is great for. It's transient data that is only useful within the context of this single page for this single user, and only while the user is on this exact page. Imagine if you had to store that piece of data in the users session. It seems harmless -- but with millions of users, that adds up to a lot of data. Data which will hang around for the user's entire session length, even though its only used for a few seconds! ViewState in this case is a _far_ more efficient way to maintain that kind of state information.

    Microsoft is not forcing anything. In my opinion it would have been better if ViewState was always off by default, or if you had to write some explicit code to get data in and out of viewstate. But it being on by default is a long way from 'forcing' anything.

  • Two things here:
    1/ I had a look at the Accordian and I think it should be expanded at the current navigation level, ie. where you currently are. And as far as I saw, it's quite easy to see in ASP.NET where you are thanks to the web sitemap etc. So I see no reason to store it somewhere.

    I see your point here: keep only some not critical data, and let your application gracefully degradate when that data is not available. But it still "doesn't speak to me", as we say in Poland ;) See - if I read your post correctly, you have to take care about deleting that data after it's been used, while in session it would simply expire. And RAM is quite cheap these days, while amount of data flowing in/out of your connection is not.

    Plus, POST is not the only way to interact with your page - there are regular GET requests, there are F5-refreshes, there are users who can manually type / paste a link to another part of your site - I would loose the whole ViewState then. Still, I can't see any valid reason to use it.

    2/ My friend was playing with VS2008 and ViewState / controls and he was not able to remove it completely. Turning it off in web.config and on control level didn't remove it completely, just made it shorter. I think we'll use the decoder to see what's inside.

    He found just one way to remove it at all - overwrite some default functions, so that they return null. But even then, you get the input field in your form.

    So yes, it looks like forcing to me ;)

    If we're wrong at what we're doing - we're just learning, you know - please correct me. I'll ask him to comment here as well detailing what he did.

    Also - a great note about the note that FORMs populate themselves with client-provided data without Viewstate and that ViewState it's not about that. When I asked a coworker who wrtoe a couple of ASP.NET sites what ViewState is really useful for, he said that it allows the site to repopulate all the data in a form that a client submitted just before.

  • An accordian was just a contrived example. If you can make it do the right thing without storing data, great. But not all accordians are used for menuing. What would you do then?

    Yes ram is cheap, but server resources are precious. You have to think about not only the amount of data you are saving, but how long it is resident for. If a session is 20 minutes and you are storing 100 bytes, thats 2000 byte-minutes, regardless of how long the user is actually on that particular page. If you store that same 100 bytes in viewstate, it only actually consumes server memory when the user actually posts the form. A user isn't likely to sit there on the same page posting it over and over again for 20 minutes are they? You'll get far less byte-minutes on the server. It seems trivial, but image 1000's of users on the site at the same time. That can quickly add up to many megabytes worth of data for something so trivial and simple.

    You can't completely get rid of viewstate. It is absolutely required in some situations by the framework. You might scoff at the notion that it is required for anything, but it is, and it has good reasons. And better to use a single hidden field for the required data -- yet somehow I doubt people would complain about it if this 'required' data were stored in a differently named field or fields. Read my post on what Page.RegisterRequiresPostBack is used for as an example.

  • You didnt understand what I mean about the accordian. I know there are nice CSS ways of creating menus. But it's got nothing to do with my point :)

  • Thanks for all the help and patience.

    It might be I'm making unnecessary noise about some things, but the idea of sending information to / from user to make my application work properly gives me the creeps.

    I will give it more read, maybe I'll find some sense in it.

  • sanjeev -- changes to the page client side are going to be lost when the page refreshes. Thats the way it is. It isn't ViewState's job to remember client-side changes to non-form elements. DDL is a form element, but only its selected value is posted by the browser, not its entire list.

    You'll have to store the items in a hidden field and use it to repopulate the list when the page reloads. Or just reload it automatically. That or don't do it client side. :)

  • Troy -- your comments about posted values and viewstate and all that are absolutely correct.

    As for OnPreInit... the work around is kind of a bummer. It's not behavior I would count on existing in future releases of the framework, so use it with caution. Overall I'd say it would probably be best to find another way of implementing what you need, but if it works well for your scenario and you don't mind having to test it with future updates and possibly fix it, then so be it. Not that there's plans to change that behavior, but its certainly not a documented behavior which always makes it somewhat subject to change.

  • you are so sick my friend
    you should live in a movie
    :)

  • Hey, I loved the article... And I am probably going to have to read it a couple of times to fully get the picture...

    Here is a question fo ryou I thought maybe you could answer.

    Can a program add *and* delete dynamically created usercontrols/controls that need viewstate to be enabled?

    An example would be like google widgets or yahoo users home page. (these aren't .net apps mind you)

    Many Thanks,

    Angela

  • Angela Law -- sure. But it depends on the process exactly if you even need to 'remove' them. It may be just be that you just 'don't add' the ones that should be 'removed', since you have to add all of them every request as it is.

  • I can't seem to get this...

    I read through your articles and I must say when it comes to .NET I am probably a toddler at it...

    But I am trying to make a dashboard where a logged in user can custom create gadgets/widgets on the page. Like google or yahoo.

    Using the Update panel and a 3rd party widget control from Telerik called dock.

    And I just don't see a way... I was trying to implement your thoughts...

    But the trigger events for the updatepanel need to be loaded for each widget control in the Oninit area. If I load them in the OnLoad area then it is not recognized and they don't fire.

    However, if I load up in the OnInit area Session and Viewstate are not available so, I can't retrieve the order of the widgets loading nor the userid.

    So, I am in a catch 22....

    Anythoughts? I been trying to resolve this for 2.5 weeks now... And I am baffled...

    No one that i am working with understands viewstate unfortunately. And the one solution someone is trying to implement is a clouge (you know fanagled)...that I think in the long run will still cause problems...

    Any help would be greatly apprecaited!

    Angela

  • Oh, one other thing... I do need to remove them... For instance someone can have up to 30 choices to place on the dashboard page...However, they are limited to 7 allowed at one time

    So they can add and delete and look at different widgets. Which means, that someone could literally look at 30 widgets.

    And these widgets are using grid with ajax, charting tooks, dropdowns, ect....

    Is it to ambish?

    Thanks again I redo appreciate... i will being reading your articles again tommorrow to see what else I missed...

    Angela

  • Angela -- its really hard to say what you should do without more specifics. It sounds to me like you may be overthinking it. Just because they can look at 30 widgets doesn't mean there have to be 30 on the page and then you remove some. Unless I'm not understanding your scenario.

    First thing I'd do if I were you is throw away the update panels. UpdatePanels do not equal instant greatness. You have to get the form working without them for there to be any hope of it working with them. Remove them, or turn off PartialRendering, and see how your page works then. If it works, great, then move on to adding in update panels. Trust me on this one. Perhaps that is one area you're getting confused with. If you have 30 things showing up on the page, it doesn't mean you have to remove them to get rid of them. Each post is a completely new request with completely new response. Removing one could be just as easy as just adding 29 of them this time instead of all of them. If you're talking about update panels that might confuse you because you think it needs to be removed somehow since there's this 'live' version of everything staying on the page after each post. Its not the right way to think about it. Each time there is a post, whether it is asynchronous or not, imagine the entire page just being thrown away completely and then rebuild from the response from the server. UpdatePanels do give you a way to update only one part of the page at a time, but its only an optimization for display purposes, nothing more! You still need to treat the postback like a regular one.

  • Angela -- here's one way I see it working. The dropdown list firing the onchange event is a postback assuming you are talking about the DropDownList.SelectedIndexChanged event. Before that event actually fires in the postback, you'll be going through Init and Load. ViewState is available in Load. From there you will need to recreate all the controls the user has added on previous postbacks. How you determine that could be from a database or it could be from viewstate, maybe session, such as through an arraylist of widget ids or something (not the widget itself mind you, just whatever you need to determine which one in the list it is). After Load, and before PreRender, is where the SelectedIndexChanged event from the dropdown will fire. In the handler, you will determine which is to be added, add it, and also update the store you are using to remember which the user has added for the benefit of the next postback. When you load a widget dynamically you should be sure to give it an ID that is specific for that type of widget to avoid a shifting ID problem. For example, each time you load an added widget, increment a counter that is stored in ViewState, and give it the id="widget" + counter, then store the ID you assigned it as part of the ViewState or Session store you use to recreate them on postbacks, so that you be sure to give each one the same ID it had last time. When removing a widget, not only do you remove the control from the page, you also remove its corresponding entry in the store so that it simply isn't recreated on the next postback.

  • This is great stuff, thanks. One more AJAX question: I understand that the ViewState won't/shouldn't know anything that is done on the client side if the page is refreshed. But when a client-side process updates a control like a drop down list, why doesn't the ViewState handle the value once the whole page is posted back?

    I have a couple of cascading drop downs (car make and model) that use AJAX. A user selects a value for one or both as part of a query. Once they have entered selection criteria in a number of fields, they submit the page and see the results. If they click the back button to alter the query, the non-AJAX fields are still populated but the drop down lists have lost their values. The controls have "Enable ViewState" properties, but this doesn't seem to work.

    After all, if I am typing a value in a field, I am a client-side process, but once I submit the form, the data is sent to the server-side where the ViewState should be able to handle it.

    Do you have any suggestions?

    Thanks, Walt

  • Walt, the list of options that appear within a dropdown are not part of the data the browser sends to the server when it posts. Only the selected value is. Just like say the width of a textbox isn't sent to the server, only its value. So there's no way the server can know about changes to the dropdown client side unless you specifically code for it (such as by using hidden fields). You can think of it in a traditional windows forms app, leaving the page and coming back is like restarting the windows app, it's going to lose changes to its initial state that were done programmatically unless you purposely saved that state somewhere and actively reconstruct it.

  • Great Article!!!!!
    I have a question though...How can i calculate viewstate size.
    specially of the ones added by the developer on the page.
    eg:Viewstate["somekey"]="Somevalue";

    Can you please help in this regard.

  • Pradeep -- the simplest way would probably be to just look at the page source, copy it into notepad, save it, and look at the file properties :) There are viewstate decoding tools out there too that would be helpful, just search for viewstate decoder and I'm sure you'll find one or two. Enabling asp.net trace also shows you viewstate size broken down by control.

  • Impressive article.. you are the best blogger about ASP.NET on the Internet.
    ScottGu should keep reading your blogs until he (hopefully) gets it and understand how it's done ;)

  • I really enjoyed reading your article, it was my first I read to get a clue on Viewstate and I found it very easy to comprehend. But how do you keep at least your own Viewstate THAT short? It's some kind of miracle, I guess.
    nice work! keep it on :-)

  • ah yes, also it's not clear to me this:
    If I call MyUserControl.DataBind() in page_prerender of the page, and there are <%# tags in the user control... will this go into the viewstate or not?

  • Mark -- don't do steps 1-3, just skip directly to 4 :)

    Seriously, your steps don't sound right at all, sorry. What you need to do really depends on, well, everything that is going on. I can't tell you that you should "delete all calls to databind of any sub controls" because theres lots of times where you do need to do that. The only way to improve your viewstate usage without breaking everything is to really look at it and understand it on a case-by-case basis. Start with one page, and just one aspect of that page.

    And yes, PreRender is before SaveViewState, so binding from there still dirties viewstate.

  • Good idea, step 4 it is ;)

    But seriously, I read the article again and I found where the problems of my confusion comes from..
    1) In "3. Persisting cheap data" you say that by overriding OnInit and databinding a dropdown inside it, the ListItems are not persisted in the ViewState. Well which OnInit do you have to override for this to happen?
    In my page I have a dropdown in a UserControl and I overrode the OnInit of the usercontrol and I don't touch it afterwards but data is STILL persisted in ViewState anyway.. (I use viewstate decoder to check this).
    And also this behaviour seems perfectly logical to me: first TrackViewState() is called in the dropdown and then OnInit of the parent UserControl is executed, and so binding the dropdown there is too late.
    What is wrong in this reasoning?

    2) And then another confusion is with the fact that in "5. Initializing dynamically created controls programmatically" you say that with this method the dynamic control is like one that is fully declaraed in the aspx page and you only need to populate it the first time... if this is the case why don't you populate the control once also in case "3 3. Persisting cheap data"... I mean it's probably even cheaper and faster retrieving it just for the first page load...

    I'm most probably wrong somewhere.. but can't find where ... any idea? shall I start look for a new profession?

  • Ok I have now seen that there is EnableViewState="false" set in the example "3. Persisting cheap data"... sorry I didn't notice this before.

    So the reason for point 1 is now clear to me :)

  • Mark --

    1) you answered yourself :)
    2) I think you missed the point of 'cheap' data. The data is cheap to get, so why not get it every request? In regard to getting the data, yes its cheaper to get it only once. But then the data is persisted in viewstate! What's cheaper, getting the data every time, or getting the data once and then allowing viewstate to maintain it for you?

    In example 5, I don't think I ever said "and you only need to populate it the first time". I wouldn't every say that in general. It depends on your needs whether you need to every time or not.

    Try not to come up with "truths" like "always do this...". The trick is to understand how it works so you KNOW what you should do, not just follow a "menu" of tricks, you're just as likely to be doing something wrong that way...

  • I am having 20 user controls within a multiview and i am able to show the user selected Activeview, but the Page_Load is called for all of the user controls.


    so I have restricted the user to process the code in page_load for the Activeview . But the application memory grows for every action within the application.How to handle the memory leak in this scenario.

    I do not know where to start to fix the issue.Please help.

  • kumaram -- just having a multiview wont cause a memory leak. If you have one, which you don't necessarily have, its probably due to whatever the controls are doing such as database access, not closing the connection, storing things in cache, etc. I say you may not have a leak because just the fact the memory usage increases doesn't mean there's a leak. The growth could be unrelated to you controls, or it could just be that garbage collection hasn't occurred yet. If you're doing the right thing in the controls (disposing of external resources like window handles or db connections) then you probably have nothing to worry about.

  • Hi,

    I'm having this weird problem. I have a custom user control with its own custom validator. I draw instances of it on a page dynamically.

    The problem is that if I draw them in the oninit phase of the page, the validate event for the custom control fires before the validate event of the page and so in the Page's validate event I can determine whether everything was ok via Page.IsValid.

    However, if I draw them on the OnLoad event of the page, the validate of the custom control fires after the page's validate event, and that just doens't work for me!

    I want to be able to draw them in the onload. Is there a way I can get the control's validate to fire before the page's?

    Also another question: You mentioned early on in the article that posted values aren't maintained via Viewstate. Then how are they maintained? If I draw my dynamic controls in the oninit or onload, then they are able to persist, but if I draw them after those events, then they don't persist values on postback. What gives?

  • Pretty good article !!! superb !!!

    Do you think is worthy to update it for 2.0 and StatControl?

  • thank you so much or the article. i even found exactly what i was looking for.
    i have a problem though. i have a dropdownlist which is bound to a object data source. i have disabled the viewstate for all the page. i managed to databind the dropdown correctly and all works fine. it's set to autopostback=true. problem is when trying to capture the "on selected index changed". the method associated is hit everytime, except when i select the first item in the list.
    i read a bit in the msdn and it says about this control that it shoul have viewstate enabled: "A list control must persist some values between posts to the server for this event to work correctly. Be sure that view state is enabled for the list control."
    is there a way to capture the "on selected index changed" everytime without using viewstate?

  • Whow im kind a new in ASP .NET 2 but Understanting, the insights of how Viewstate Works is truly a Gurus thing.
    Thanks a lot For this journey into Viewstate Internals, and its 5 Rules Of Thumb!
    Cheers from Portugal

  • Good Article.

    I appreciated the humour. If it had been a completely dry article I would probably have never persevered to the end!

  • I just read your article and has been very helpful in clearing up the unexplained fog of viewstate. I have a question related to viewstate and callbacks. I understand how I can refresh the controls on the page by using
    _theFormPostData = ''; and then WebForm_InitCallback();

    Here is my situation: I have multiple callbacks on a page. I have a custom object that contains some significant information that is used from one call back into the other.

    the object gets initialized at page load. I retrieve the pageload value at callback1... callback1 sets a new value to the same key in viewstate and callback2 is supposed to retrieve the callback1 value.

    But this is what happens when I retrieve the value from the view it is always the value that was set in the page load. How can I make the viewstate retain the value from callback to callback.

    Thanks,
    Sadia

  • Hi Dave,

    Thanks for education on ViewState - very interesting. The basic rule of thumb I'm getting out of this is that controls that get populated inside the "if(!IsPostBack)" of Page_Load should use the ViewState for successive posts. But controls that get populated on the "else" or every call should leave the ViewState alone. In my current application, the controls inside the "if(!IsPostBack)" are dropdowns that contain somewhat dynamic data from a database - so i'm sacrificing viewstate in exchange for minimal trips to the database. (while the data is dynamic in nature, its static enough to take a snapshot for the life of the session.)

    Thanks again!
    Curt -- PhillyPa


  • Sadia -- Callbacks do not update viewstate that resulted from the post. To do that you've have to switch to using an UpdatePanel, which maintains everything.

  • If "Callbacks do not update viewstate that resulted from the post", then at what stage of the page life cycle should I initizalize the viewstate with the required object, so I can update it in the callback and it will maintain the view state.

    I would love to use update panel, but the team I am working is somewhat anti update panel.

    Thank you for your help.

  • Sadia -- you simply can't with callbacks. ViewState is posted to the server when a callback occurs, but the new viewstate from the response does not get send back to the client. Therefore each callback you make will always be with the same viewstate you had when the page first loaded.

    UpdatePanel does maintain viewstate round trip. Why are they anti-updatepanel? A callback that also updates viewstate (if one existed) is actually pretty much exactly what update panels do. You can't want what update panel does but still not like update panels :)

    What you will have to do send the data you need back in the callback result, store it in a hidden field or a javascript variable, and just keep it going back and forth yourself, without relying on viewstate to do it for you automatically.

  • I think one of the major confusions for developers is not understanding that "input" controls such as textboxes, checkboxes and radiobuttons can use both viewstate or the IPostbackData handler to maintain/restore their values.

    Even if an "input" controls viewstate is off during a postback, because these controls implement the IPostbackData interface they restore their "posted" values from the form to the input control.

    Check it out for yourself by switching off viewstate on input controls (e.g. a textbox), causing a postback, and looping over the request.form using a foreach loop in the code behind.

    Notice the input values still get submitted and restored?! And that's the key to what happens when viewstate is off for an input control. When you do a simple postback - it uses this request.form value to repopulate the input controls.

    However, this doesn't mean that input control properties (such as the "text" property) are not stored in viewstate - because they are. Remember that "Text" is "property" of a textbox (and remember viewstate stores "properties" of controls) - therefore the textbox "Text" property IS stored in viewstate.

    In my first example described a very simple postback to repopulate the controls.

    Here's and example of when an input control (a textbox) uses viewstate to maintain it's "Text" property.

    1. Create a aspx page with two panels.
    2. Panel1 has a textbox and a button (that causes postback) and the panel1 is visible.
    3. Panel2 has a button only (causes postback) and is invisible.
    4. In the codebehind, handle the Button OnClick event for Panel1 and by making Panel2 visible and Panel1 invisible.
    5. Handle the OnClick event of the button in Panel2 by making Panel1 visible and Panel2 invisible.
    6. Now, load the page and add some text into the textbox of Panel1 and cause a postback - panel2 appears with a button.
    7. Now click on the button in Panel2 and make Panel1 visible. Notice that the textbox maintained the value you initially submitted? This is because it used viewstate to store the "Text" property of the textbox.
    8. Now switch off viewstate on the textbox and try the same process again. Notice that the textbox loses it's value when you return to panel1?! Proving that input controls do use viewstate to store their properties as well as using the IPostbackData interface to reload their values on postback.

    Hope this helps......

  • excellent article
    thx a lot !

  • I've been at this for hours until I finally found your article - working now - thanks!

  • Thanks for a great article. I wasted a day and half trying to get ViewState to make my coffee. If only I'd read your article first!

  • Awesome article! thanks for putting it altogether!. I never understood Viewstate this clearly until I read this article.
    However, I am facing a weird problem with not using Viewstate for a datalist, which I have tried to outline below. Any feedback will be highly appreciated!
    I have a Datalist with Edit &amp; Delete capabilities, so I have the OnEditCommand, OnDeleteCommand, OnUpdateCommand &amp; OnCancelCommand event handlers defined on this datalist.
    Note: the Edit &amp; Delete buttons are inside the ItemTemplate &amp; Update &amp; Cancel buttons are inside the EditItemTemplate
    If I have the Viewstate enabled on the datalist &amp; have the databind() called in the condition if (!IsPostBack), everything works fine.
    But since I do not want the data in the datalist to be carried around in the Viewstate, I do the following:
    1) Disable Viewstate on the datalist
    2) Call the databind() without the if (!IsPostBack) condition - i.e. rebind datalist on each request
    The behavior now is as follows:
    1) On pressing Delete button, the delete command execute successfully (OnDeleteCommand event fires successfully) - row gets deleted.
    2) On pressing the Edit button, the Edit command execute successfully (OnEditCommand event fires successfully) - row is displayed in Editable mode
    3) Once in Editable mode, if I press Cancel button, this event also fires successfully &amp; Editable mode disappears
    4) But on pressing the "Update" button, the OnUpdateCommand event does not fire at all ! (record changes do not get updated).
    What would be the reason that all other events fire except the UpdateCommand?
    Note: I also have a "View Details" button defined in the ItemTemplate - which takes the user to another page for viewing further details of the current item. For this I have an OnItemCommand event handler also defined for the datalist. This event also executes fine. It is just the UpdateCommand not firing sucessfully.

  • KSK -- the DataList is going to revert to its original state each request. That means it wont remember which row was being edited.

    Take this advice -- put a regular button somewhere on your page (outside of the datalist). It wont do anything but cause a postback. Whenever you are developing a page, especially if you are turning off viewstate, you should test what happens if all you do is push that button. Currently, after editing a row, then clicking that button, you will see the datalist return to a non-edit status. So you arent getting the update command because the datalist isnt even in an edit state! To keep it in an edit state, you have to set the EditItemIndex on every request, it isn't going to remember it for you since you disabled viewstate.

  • Yes! setting the EditItemIndex on everyrequest did the trick!
    Here is how I did it (for others like me who come looking for a solution:=):
    1) I stored the EditItemIndex value in a hiddenfield (defined outside the datalist - so that it is in viewstate). The hiddenfield will have no initial value
    2) In OnEditCommand event handler:
    datalist.edititemlndex = e.item.itemindex;
    hiddenfield.Value = e.item.itemindex.ToString();
    DoDatabind();
    3) In page_load:
    if (!IsPostBack)
    &nbsp; &nbsp; DoDatabind();
    else
    {
    &nbsp; &nbsp;if (hiddenfield.Value != "")
    &nbsp; &nbsp;{
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; datalist.edititemlndex = Convert.ToInt32(hiddenfield.Value);
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DoDatabind();
    &nbsp; &nbsp;}
    &nbsp; &nbsp;else
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;DoDatabind();
    }
    4) In OnUpdateCommand event handler:
    DoUpdate();
    datalist.edititemlndex = -1;
    hiddenfield.Value = ""; // this is required to get out of editmode on postback
    DoDatabind();
    That's it!
    I spent 1.5 days trying to research this issue - I wish I had come across this article earlier!. Thanks for coming to my rescue:=)

  • Excellent article. It really helped clarify any viewstate questions I had and your examples were good at re-enforcing everything and giving me a solid understanding of things I may not have caught right away.

    Thank you.

  • I would find it useful if you would add an addendum covering how some controls look like they're using ViewState when they're really not.

    http://support.microsoft.com/?id=316813
    and
    ControlState

  • Thanks for your clear explain about viewstate .

  • Awesome article, finally I can understand write more efficient web form with less VIEWSTATE

  • Hi,

    Awesome article. I'm looking for an elagant way to do the following:

    I nead to dynamically generate a control depending on the result of a control post pack(let's say a dropdownlist)

    Here is my work around method:

    protected void Page_Init(object sender, EventArgs e)
    {

    int Mode = Convert.ToInt32(Page.Request["Mode"] ?? "0");
    if (Mode == 1)



  • Awesome article.

    I'm looking for an elagant way to do the following:

    I nead to dynamically generate a control depending on the result of a control postback(let's say a dropdownlist)

    Here is my work around method:

    protected void Page_Init(object sender, EventArgs e)
    {
    //Page init where I would create a control depending
    //on the dropdownlist selection
    int Mode = Convert.ToInt32(Page.Request["Mode"] ?? "0");
    if (Mode == 1)
    {
    //Create Control 1
    }
    else(Mode == 2)
    {

    }
    }

    protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
    {
    Server.Transfer("./DetailView.aspx?Mode=" + DropDownList1.SelectedValue);
    }

    Ideally I'd prefer to just use the DropDownList1.SelectedValue.
    As I can only use the DropDownList1.SelectedValue in the Onload event I'd have to create my controls in this event as well. This of course would mean that the viewstate would be incorrect for the generated controls. How would you approach this problem. Is this the best solution?

  • Laredo -- You should look at my article on understanding dynamic controls, and specifically the one 'by example' with an attached project that demonstrates it.

  • Alex -- been so long you probably wont see my reply, but here it is anyway. When you create a control dynamically, it hasnt loaded its viewstate until you add it to the control tree. So you are setting the value and then viewstate loads, changing the value. In this case it is also loading postback data, which further reloads the value. I'm not sure why you wouldnt want a textbox to keep the user entered value on a postback, but you will need to change the value after it has already loaded postback data in that case. For a control added dynamically from OnLoad, that would be in PreRender. If added in OnInit, then OnLoad would work. This behavior by the way exactly mimics what you get with a statically declared control and should be what you would expect -- the declared value is set on the control's property every request, too. Just that it is done for you automatically so you don't think of it that way.

  • Thanks for this great article. It really helped me to understand viewstate lot better :)

    just needed to clarify one thing

    I did a test to clarify my understandings on the viewstate. I created a button in the OnInit method during !IsPostBack and a Label control during the PostBack. I assigned a text to the Button control. When I clicked on the Button, the button control disappeared as expected but I was suprised to see the Label control taking the text of the button. if the viestate uses ID's to reload the state data, then how is this happening?

  • pmatsinopoulos -- because the command itself is not saved in viewstate like most other properties are. Only the parameters to the command are viewstate managed.

    Why that is? You really should not put such a thing in viewstate. You have to consider anything that is viewstate managed to be controllable by the end user, because unless you are encrypting your viewstate it can be manipulated -- and then even if it is encrypted, its better not to put stuff in viewstate that you dont need to.

    Its also probably wasteful to put the command in viewstate. You probably only have a small set of possible commands, right? Or maybe there's a large set of possible commands, but they only vary in some small way, correct? Better than to put only the data which you will need to reconstruct the command in viewstate, then do so dynamically, than to just put the entire thing in viewstate. That limits the realm of possibility if someone where to gain control over viewstate, they would still be limited to the commands you build from the data (which you would be ensuring are within acceptable ranges).

  • jshallard --

    If you look at what the default delete/select/etc buttons do, they post a command that is like Delete$5. That means delete what was in row 5. The ListView/GridView/etc uses that to issue the command for the appropriate row. The problem you describe arises when you use command bubbling, rather than this direct-to-the-control post command. Your solution with command bubbling is fine, but it can't be a general solution baked into the control. A command can bubble for any reason what-so-ever, it's not always the result of a post, or from a post of a particular type. Anyone can call RaiseBubbleEvent for any reason, so its not a feasible general solution.

    As for the seemingly wasteful double databinding -- it does seem wasteful, but maybe not as bad as you think. First of all, the fact you databind twice doesnt mean you have to retrieve the data twice. And its quite likely that the 2nd databind is necessary to ensure the control is reflecting the data instead of user-entered values or things that have been dynamically changed across posts. The 1st binding consumes viewstate and postdata, 'completing' the life cycle of the controls from the previous request. The 2nd binding starts a whole new sequence. This happens even when viewstate is on, by the way, just that the first binding is utilizing viewstate and the second is utilizing the data.

  • This was an extremely useful article. Thank you for putting it together. I've been trying to get a handle on the ins and outs of ViewState for quite some time. I had read dozens of articles on the subject but as you say, none of them give a complete picture.

    And for the record, I enjoyed the humor as well.

    Ken

  • Excellent article. I'm a fairly experienced developer but just beginning with ASP.NET. Not onlt did this help me understand ViewState, but also ASP.NET issues in General.

    Also, I LOVE the style of the article with the humor, etc. It kept me captivated much more than if it was absent. Thanks for taking the time to write it.

    Stu

  • And I was thinking I was the problem...

    I can't believe such important stuff is ignored in so many otherwise good books.

    Let me know when you publish a book, it's a must-have.

    10x !

  • This was a very helpful article and this might be a noob question. Since .net uses viewstate to store the values of control properties that have changed, can you access viewstate on postback to determine if one of those properties (say the text property of a textbox) has changed? Not on a custom control though, just the regular TextBox control.

  • Excellent article, thank you!

  • your article is fantastic .I've got a problem that drive me mad!!!
    I have to create some controls in PreRender() event .the controls events don't fire at all.

    Please guide me.

  • Best article ever.

  • Keep it up doing these great kontent correct articles!... imagine all out there to be like this one...

  • One of the best article I have ever come across over the net. I have shared this with as many web developer as I can.
    Great and Simple explanation with humor to make things go easily in mind.
    Thanks a lot...

  • Nice article. I am still confused though. You say that form items intrinsically keep their values.
    eg. User enters "blah" in text box which has been persisted in ViewState. This form is now posted back. Now when LoadViewState() is called wouldnt that mean that the value entered by the user will be overwritten by the ViewState?
    Cheers

  • brianstewey -- No, because postback data is loaded into controls after they've already loaded their viewstate. This is how, by the way, the textbox knows whether to raise its 'TextChanged' event.

  • Th guy ranting about too much humor is an Ass

  • This is the best article on viewstate...ever. Thanks for taking the time to write it. I just emailed it on to my team.

  • Great material.. made my day..
    Thanks a lot

  • is view state is expired?

  • I Have a custom control where I create Controls dynamically based on XML. I use CreateChildControls().


    Here is the code how I create Controls..

    protected override void CreateChildControls()
    {
    CreateParameterControls();
    base.CreateChildControls();
    }

    private void CreateParameterControls()
    {

    this.Controls.Add(new LiteralControl(""));

    foreach (XElement xe in this.Parms)
    {
    this.Controls.Add(new LiteralControl(""));
    bool required = xe.Element("REQUIRED").Value.Equals("true");
    string type = xe.Element("CONTROL").Element("TYPE").Value.ToUpper();
    string id = xe.Element("NAME").Value.ToString();

    Control control = null;
    Label label = new Label();
    label.Text = xe.Element("CONTROL").Element("LABEL").Value.ToString();
    label.ShowRequired = required;
    this.Controls.Add(label);

    System.Web.UI.WebControls.RequiredFieldValidator validator = new System.Web.UI.WebControls.RequiredFieldValidator();
    validator.Text = "";
    validator.Display = ValidatorDisplay.None;
    validator.SetFocusOnError = true;
    validator.Enabled = required;
    validator.ErrorMessage = xe.Element("CONTROL").Element("LABEL").Value.ToString() + " is required";
    validator.ControlToValidate = id;
    this.Controls.Add(validator);

    this.Controls.Add(new LiteralControl(""));


    if (type.Equals("TEXTBOX"))
    {
    control = CreateTextBox(id);
    }
    else if (type.Equals("DROPDOWN"))
    {
    control = CreateDropDown(id, xe.Element("CONTROL"));
    }
    else if (type.Equals("DATE"))
    {
    control = CreateDate(id);
    }
    else if (type.Equals("CHECKBOX"))
    {
    control = CreateCheckBox(id);
    }


    if (control != null)
    {
    this.Controls.Add(control);
    }

    this.Controls.Add(new LiteralControl(""));
    }

    this.Controls.Add(new LiteralControl(""));

    }

    However after the post back none of my childcontrols displays the data posted.

    What could be the reason its not loading the previous state?

    thanks in advance

  • I have several formView pages that seem to be getting some kind of viewstate time out. If I let the page sit for 20 min or so and then hit a control that causes a postback, ViewState.Count==0 on the next PageLoad. This happens on a number of different pages and can be reliably reproduced. It causes problems in various parts of the codebehind that are relying on ViewState data. It is not a session timeout issue as session timeout is set to 240 min and the session is still intact. Yet I don't find many internet posts on ViewState timing out. Do you have any ideas about what might be going on here?

  • I have spent my whole day reading this but I gotta say it's outstanding and I did LOVE your style of writing :)

  • Our solution to the 20 minute timeout problem was to change sessionState from inproc to sqlserver.

  • Amazing article... For more than 3 years looks like it's been very helpful.

    Congratz ;)

  • I should have read this article a year ago.. Simply, great.. Thanks!

  • Excellant Article....Thanks for sharing...

  • So I'm confused. I've implemented the "persisting cheap data" sample in a ASP.NET 3.5 app using a web form w/ no master page. As is, the drop down list's selectedIndexChange event is always fired if the first item is not currently selected. It makes sense to me that this is happening, but is this the expected behavior??? Seems bad to me.

    I've tried binding OnPreInit which works as described above; however this approach doesn't work when a master page is used. In OnPreInit, the controls are not available to bind to when a master page is used. Am i missing something?

  • Joe -- SelectedIndexChanged requires that it knows what the previous value was, so without viewstate, that's just the way it is. I won't remember what the last value was, it thinks it is whatever you declared the value to be (default 0). Also, for OnPreInit, try doing it after calling base.OnPreInit.

  • Thanks for the article, it reminds me a what a kludge the .net framework and viewstate really is...
    It's too easy for people to write non-performant applications in .net, the whole postback back model is depends on HTTP POST which generally will always require more work than a GET
    Coders have to remember to turn viewstate off for controls (and remember why) other wise pages quickly bloat - and because viewstate relies on the post the traffic penalty is both upstream and downstream
    All the .net pages I've seen are littered with javascript at odd points , this can cause rendering problems, all the extra inline style tags add weight.
    Look at some of the front end performance work people like Steve Souders et al are doing and then look at what .net generates by default and you'll see why I dislike having to support a .net based web app
    Andy

  • In response to a submit button, which is capturing a variable parameter on the page, I am dynamically creating (multiple) xmldatasources and dynamically creating gridviews using the xmldatasources, which have a checkbox item in one of the columns. I am querying multiple distributed databases to build the data, and the number of datasets returned varies, which is why I build the gridviews (and their underlying xmldatasources) dynamically.

  • in "Persisting cheap data"
    i don't understand how does it solve any problem:
    so once i have disabled view state and moved data binding to oninit, on postback the previous selected value won't be remembered and i don't think this is desired behaviour? the only benefits is that states won't be persisted. am i right in saying that? thanks.

  • I have a DropDown(AutoPostBack= true) with two values "P" and "Q". I have another custom webControl called TextBox which have property called LabelMode which would make textbox as label on true and viceversa. The LabelMode Property is set using ViewState and not using private variable.
    Now i want
    If( dropdown.selectedValue = "P)
    {
    amount.labelmode = false;
    }
    else
    {
    amount.labelmode = true;
    }
    suppose by default labelmode = false;
    now suppose we select from dropdown as "Q" then it will set labelMode= true; but even though it is set to true after page is load it has value of false, in it then again if i change value of dropdown i.e. again postback it retrieves the oldvalue ie. now it will have value of true.

    I have tried calling the above code on prerender() and databind() events,but nothing seems to be working.

    please help

  • Great article. Solved our puzzle on viewstate.

    Will start optimizing our websites.

  • Hi Dave

    I wish I could have read this article 4 years ago! Well, life is like that only.

    One question: How can I get rid of ViewState completely. I am using pure AJAX callbacks in javascript for everything. I just don't want those hidden inputs at all. Is it possible.

    -@bhi

  • The only way to drop the hidden fields completely is to not have a form, or at least not one with runat="server". Some controls require one though, so may not be feasible if you are using them.

Comments have been disabled for this content.