Managing State
With user controls and composite custom controls, you don't have to maintain state because the controls you add already manage state for you. However, this situation changes with rendered custom controls because you must handle all the work yourself. More specifically, you must retrieve control state and work with the ViewState state bag directly. For example, here's the Rating property code that reads and writes to ViewState to persist its state:
// holds the state of the rating [Bindable(true), Category("Appearance"), DefaultValue("")] public int Rating { get { int rating = 0; if (ViewState["Rating"] != null) { rating = (int)ViewState["Rating"]; } return rating; } set { ViewState["Rating"] = value; } }
To manage control state, you need to implement the IPostBackDataHandler interface, which specifies the LoadPostData and LoadPostDataChangedEvent methods. Listing 3 shows how to implement these methods:
Listing 3 Implementing IPostBackDataHandler
// Load postback data back into properties // and tell ASP.NET that an event must be // raised for values that change. public bool LoadPostData( string key, NameValueCollection postData) { bool eventRequired = false; int postBackRating = Int32.Parse(postData["Rating"]); if (Rating != postBackRating) { Rating = postBackRating; ratingChanged = true; eventRequired = true; } return eventRequired; } // Find out what type of event must // be raised and call the applicable // method. public void RaisePostDataChangedEvent() { if (ratingChanged) { OnRatingChanged(); } }
When a control implements IPostBackDataHandler, ASP.NET calls the LoadPostData method. If the LoadPostData method returns true, ASP.NET calls the RaisePostDataChangedEvent method.
The string parameter for LoadPostData holds a key value identifying the current control; the NameValueCollection is a collection of control state items you use to repopulate properties and check for modifications. The implementation in Listing 3 checks whether the Rating property has changed. If so, it updates the Rating property with the new value and configures eventRequired so the method can return true and invoke the RaisePostDataChangedEvent method.
The RaisePostDataChangedEvent method in Listing 3 checks which value changed and calls the appropriate method to raise an event. In this case, it's the OnRatingChanged method, which raises an event that could be hooked up to event handlers. This pattern enables the control to notify callers when certain values in the control change.
TIP
Be sure to call Page.RegisterRequiresPostBack(this); in the Init event of the control. Leaving this out will result in the LoadPostData event not being called when there wasn't any original ViewState for the control. Sometimes you can add a "name" attribute with its value set to "this.UniqueID" to at least one of the controls being drawn in the Render method; however, the UniqueID trick doesn't work all the time, so calling Page.RegisterRequiresPostBack(this) is the better technique.