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


Custom Web Controls Demystified, Part 2 : Page 4

In Part 1 you learned how to build a custom rendered control. In Part 2 you'll learn how to build a composite control.

Styling in rendered Web controls can be a bit tricky but if handled correctively, is key to their versatility and reusability. The more styling you can provide for a Web control, the more places you can reuse it and make it look different. The first thing you need to do is set up the styling properties that you'll expose in your Web control. The FormField control is going to have three styling properties: CaptionStyle, FieldStyle, and ButtonStyle; but for the purposes of this article, I'll only walk through CaptionStyle in detail.

The CaptionStyle property, like the other style properties, will be of type Style. .NET uses other styling types but they all ultimately derive from Style. It is the Style type that contains all of those great properties that you've worked with in the past: BackColor, ForeColor, Font, and many others, including CssClass for attaching a style sheet. You can also create your own custom style types, but that's beyond the scope of this article. Unlike the other properties, persisting in the ViewState will be done a bit different. You need to set up member variables to act as the internal store for your properties, much like how you set up properties of a business object.


   Private _CaptionStyle As Style = New Style
   … other code …
   Public ReadOnly Property CaptionStyle() As Style
   Return Me._CaptionStyle
   End Get
   End Property
In C#:

   private Style _CaptionStyle = new Style();
   … other code …
   public Style CaptionStyle 
   return this._CaptionStyle; 
The first thing you'll notice here is a read-only property. This is often the case with properties that are of an object type. To explain this better, let's skip ahead and pretend that you have a finished control and are using it on a Web Form. Your control, called fldName, has a property called CaptionStyle. If you wanted to set the font weight to Bold on this property from the code-behind class, you would do something like this:

   fldName.CaptionStyle.Font.Bold = true;
This way of accessing the CaptionStyle property requires only the property get accessor. The set accessor would only be hit if you set the property like this:

   Style myStyle = new Style();
   myStyle.Font.Bold = true;
   fldName.CaptionStyle = myStyle;
This can certainly be done but rarely is, nor can you rely on users of your controls to set styling properties in this manner; so for your purposes here you will go with a read-only property. Notice that you don't have ViewState code in the property, so you're probably wondering how to persist the value of _CaptionStyle, because more often than not, you will be hitting this property using its get accessor only. Placing ViewState code in a set accessor, even if one existed, would not be hit. For that reason, you must persist the _CaptionStyle variable in another way, though ultimately still in ViewState.

There are three methods you override to handle specific state management situations like this one. Before, you were reading from and setting a value in the ViewState variable. Now you run into a situation where you would be able to read from it but not set it. By overriding these methods, you can persist your member variable, _CaptionStyle, into ViewState along with any other values as well. The methods you need to override are called SaveViewState, LoadViewState, and TrackViewState, and are part of the IStateManager interface, which the control class automatically implements by way of its inheritance. Complete explanations as to the exact implementation of this interface is beyond the scope of this article, but you do need to know that this interface is used by any control or object that needs to persist some kind of state using ASP.NET's ViewState mechanism. The Style object which defines the style properties also implements IStateManager. Let's take a look at what the SaveViewState method will look like.


   Protected Overrides Function SaveViewState() 
      As Object
      Dim state() As Object = New Object(4) {}
      state(0) = MyBase.SaveViewState()
      state(1) = CType(Me._CaptionStyle, _
      state(2) = CType(Me._FieldStyle, _
      state(3) = CType(Me._ButtonStyle, _
      Return state
   End Function
In C#:

   protected override object SaveViewState() 
      object[] state = new object[4]; 
      state[0] = base.SaveViewState(); 
      state[1] = ((IStateManager)
      state[2] = ((IStateManager)
      state[3] = ((IStateManager)
   return state; 
If you follow this code, you see that it is building an array and storing in it the value returned from the SaveViewState method of the style member variables. Note that because the IStateManager interface methods are implemented in a protected way, you have to cast the variable to the type of the interface before accessing any member. The first subscript of the array calls the base method. This is extremely important for persisting all base object data all the way up your inheritance tree. Essentially you end up with an array of information where the first subscript is the entire array of its base class. The final array is returned as an object type by the method. This and the other methods I am about to describe are called by whatever page uses your controls during its page lifecycle (see Sidebar 1). This takes care of saving your state when at the appropriate time; now how do you load it back after a postback?


   Protected Overrides Sub LoadViewState( _
      ByVal savedState As Object)
      Dim state() As Object = Nothing
      If Not savedState Is Nothing Then
         state = CType(savedState, Object())
         CType(Me._CaptionStyle, _
         CType(Me._FieldStyle, _
         CType(Me._ButtonStyle, _
      End If
   End Sub
In C#:

   protected override void LoadViewState(
   object savedState) 
      object[] state = null; 
      if (savedState != null) 
         state = (object[])savedState;
The LoadViewState method performs the reverse of what the last method showed. Here you're receiving an object which you're then casting into an object array. Then you just extract each member and fill in the member variables. Note once again that the first subscript is reserved for the call to the base class.

You can use these methods to persist any variable in your class. You would replace calls to the SaveViewState and LoadViewState within the methods with simple variables. For example:

   state[1] = myVar; // in SaveViewState
   myVar = state[2]; // in LoadViewState
If you wanted to, you could have set up all of your properties like you normally do in business objects, which means you simply expose member variables in every case. Then you would have to persist all the member variables using these method overrides. There is one more method I want to briefly mention but without code examples. The TrackViewState method override calls the TrackViewState on any variables to be persisted that implement IStateManager, such as the style variables in this case. This ensures that all objects that should track state for themselves are doing so.

There is one more piece of code you need to put into your style property statements before you return the internal member variable.


   If Me.IsTrackingViewState Then 
      CType(Me._CaptionStyle, _
   End If
   Return Me._CaptionStyle
In C#:

   if (this.IsTrackingViewState) 
   return this._CaptionStyle
This code ensures that the style objects track their state every time they are accessed, provided your control is tracking state as well. The default condition for your control is true, but just in case you turn state off, you want that to carry over into your state-tracked objects.

That covers it for the style properties. Using this method, you can add as many style properties as you want. Now the trick is to use the values of the Style object to decorate the HTML you are rendering. The downloadable code shows you the complete code for this, but here I'm going to demonstrate using just three values of the Style object:, Font.Name, Font.Bold, and CssClass; and I'll also only deal with the CaptionStyle property.

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