RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Web Control Enhancements in ASP.NET 2.0 : Page 2

ASP.NET 2.0 does not break any existing controls from 1.1, but it adds a whole bunch of new ones, as well as several new technologies for control development.

Enhancing an Old Friend
The custom EmailContact Web control (see Figure 1) allowed you to provide your sites with a "contact us" form, complete with e-mailing functionality. In this article, I'll enhance that control with the functionality I summarized at the beginning of this article.

Figure 1: The EmailContact control in its default state.
A New Base Class
For a while now, developers have derived their visual Web controls from the WebControl class. I say "visual" because controls that do not render anything to the browser are typically derived from the Control class. This has not changed and you should continue to use the Control class for any controls that perform invisible functionality or render anything other than visual HTML to the browser. You should also continue using the WebControl class for any controls you develop using the rendering technique. However, most of us develop composite controls in order to leverage the power of existing controls. In this case, you've always inherited from the WebControl class, but you've also been forced to remember a few other details—and forgetting them has always caused a lot of grief.

Composite controls must implement the INamingContainer interface and need to be included by your control class. This interface ensures unique tag naming in all the HTML tags that your control and any controls in its control hierarchy may render. This is crucial in case you have more than one composite control of the same type on a single page. In such cases, you need to ensure that any child elements render with unique names. Forgetting to implement the interface causes all sorts of problems.

Prior to ASP.NET 2.0, composite control developers also needed to remember to call EnsureChildControls in the Render method of a control. My previous articles showed you how to override the Render method and make this call just before calling the Render method of the base class. This step is necessary for the control to render correctly in the design surface of Visual Studio. Forgetting this detail caused some inconvenience.

These two steps were so common in composite controls that many developers built a base class that included these two details and then derived all of their new composite controls from the base class. ASP.NET 2.0 offers the (appropriately named) CompositeControl instead. Use this class to build your composite controls and you'll never again have to remember to implement INamingContainer or perform an EnsureChildControls call from the Render method.

There are a couple of other new base classes that deal with data bound controls and so forth, but I'll make them the topic of a future article on data binding custom controls.

I've always preached that ViewState can be your best friend or your worst enemy depending on how you use it. If you've had trouble in the past deciding on when, where, and how to properly use ViewState, I once again direct you to my previous articles. However, if it's a topic with which you feel comfortable then you're going to love the new ControlState.

With the new Template Editing features, your controls can have the same functionality as commercial controls with very little work.
One of the biggest gripes about ViewState was its all-or-nothing approach to state management. A page developer could easily decide to turn ViewState off at either the control level, the page level, or on the entire site (via web.config). In fact, if you can turn it off in the web.config for an entire site, guess where else you can turn it off? That's right—in machine.config—in which case it will affect every site on that server. Tell me the practical joke possibilities are limitless with that one. Should a page developer decide to turn off the ability to maintain state in the ViewState, your controls may be rendered partially incapable or worse, totally useless.

Microsoft created ControlState for solving just that problem. Page developers cannot turn ControlState off, so using it is safer for selected properties.

Using ControlState is almost the same as using ViewState. However, ControlState does not have a variable like the ViewState variable. ControlState offers methods called SaveControlState and LoadControlState that your controls can override. These methods work identically to the SaveViewState and LoadViewState methods, which I've described thoroughly in my previous articles.

Because ControlState lacks a variable to use in property statements, you have to revert back to the member variable/property statement notation that ASP.NET developers have used in their objects since the forming of the cosmos.

   Protected _MailServer As String = "First name:"
   Public Property MailServer() As String
         Return _ MailServer
      End Get
      Set(ByVal value As String)
         _MailServer = value
      End Set
   End Property
However, because I'm using a standard member variable as my value store, I need a way to persist the data in the ControlState, and that's where the aforementioned methods come in. As in their corresponding ViewState cousins, ASP.NET will call these two methods within the page lifecycle. The SaveViewState method returns an object type which will be persisted. Multiple values are persisted by this method by returning an object array. And just as it occurs in the SaveViewState method, it is customary to use the zero position of the array to make a call to the SaveControlState method of the base class.

   Protected Overrides Function SaveControlState() As Object
      Dim state() As Object = New Object(2) {}
      state(0) = MyBase.SaveControlState()
      state(1) = _MailServer
      Return state
   End Function
The LoadControlState method receives an object as an argument. This object is the one previously returned in SaveControlState. In this method I reassign the member variables by casting the argument to an object array, then obtaining each subscript's value. As before, I use the zero position of the array to make a call to the LoadControlState method of the base class.

   Protected Overrides Sub LoadControlState( _
      ByVal savedState As Object)
      If savedState IsNot Nothing Then
         Dim state() As Object = CType(savedState, Object())
         _MailServer = CType(state(1), String)
      End If
   End Sub
By using these methods to persist data, the control becomes immune to page developers' evil and twisted attempts at application chaos if they turn ViewState off.

In case you're wondering where ControlState gets stored; it is another hidden textbox rendered to the HTML page. As in ViewState where the persisted data gets stored in the __ViewState hidden textbox, ASP.NET uses the __ControlState hidden textbox to persist ControlState data.

Microsoft didn't give developers the ability to use ControlState inherently as they did in the case of ViewState. You need to register your control for ControlState use. You do this by overriding the OnInit event of the control and calling the RegisterRequiresControlState method of the Page object.

   Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
      If Page IsNot Nothing Then
      End If
   End Sub
Now you can use ControlState to persist data you deem as important enough that your control is rendered useless if it's not persisted.

Remember, changes to a property you make in design-time are hard-coded into the control's ASPX declaration and are thereby automatically persisted between postbacks. However, if an action on the form changes a control's property, it will invoke the use of a state mechanism. Without that property being stored in one of the two state-stores, it will revert to the "hard-coded" state upon the next postback.

Now I ask you to please use good judgment when deciding which state storage you will use for your control properties. In general, store appearance-related properties in ViewState and behavior-related properties in ControlState. That way, if a page developer turns ViewState off, your control may not look right, but it will behave correctly.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date