Getting Data Source Elements
method is invoked during the binding phase to retrieve an enumerable object to use as the data source. The same method is also used to build the control's user interface when the page posts back. In this case, no DataBind
method is ever invoked. So who's the caller?
Under certain conditions, CreateControlHierarchy
is invoked from within the CreateChildControls methoda protected overridable method defined on the root Control class.
protected override void CreateChildControls()
// Clears all child controls
// If the control is being redrawn because
// of a postback, restore from the ViewState
if (ViewState[ViewStateItemCount] != null)
If there's no valid information at the known location in the ViewState, the method exits; otherwise, it requires the creation of the control's hierarchy from the ViewState.
As in Listing 3
invokes a method named GetDisplayData
. This method retrieves the enumerable collection of data for building the control's user interface. The full source code of the GetDisplayData
method is shown in Listing 5
. The method always returns a non-empty collection with as many elements as there are (or there should be) items in the final control. If called from within a binding operation, GetDisplayData
just returns the contents of the DataSource
property. If called from within a ViewState load operation, the method returns a properly sized, but empty array. The size of the array is read from the ViewState and reflects the number of bars to display.
Note that most ASP.NET controls persist just one value in the ViewStatetypically, the number of rows to rebuild. This behavior is arbitrary and merely suggested by the control's architecture. There's no limitation or problem in persisting more values.
A data-bound control written in accordance with the rules and guidelines hitherto detailed offers two key benefits. First, it works as expected and survives postbacks in the most efficient way. Second, it has a neat and modular internal architecture that is fairly easy to understand, modify, and extend.
There's no need for you to add a Render method unless you want to add styling capabilities to the control.
Styling the Control
The richer a control is, the more it requires visual attributes. A realistic implementation of the BarChart control, for example, would require border, font, and colors for title, subtitle, footer, bar, and labels. Each property is fairly easy to code, but the overall number of properties would soon make it unmanageable. So what's the way out? Style properties.
A style property groups in a single object a variety of visual and graphical settings. In addition, it leaves to the control infrastructure the burden of applying style attributes to individual elements. Finally, Visual Studio .NET 2003 provides great support for styles through the expandable editor in the Properties window of the solution. Overall, reasoning in terms of styles rather than properties makes the whole approach more neat and elegant.
Here's what a style is in this context.
private TableItemStyle _titleStyle;
public virtual TableItemStyle TitleStyle
if (_titleStyle == null)
_titleStyle = new TableItemStyle();
// Can initialize the header HERE
ism = (IStateManager) _titleStyle;
property is of type TableItemStyle
and represents the visual settings for the title row. A similar property is defined for the subtitle, footer, label, and bar. For example, you can visually choose the border of the bars, the header's font, the width of the labels, and whatever else you like.
If the TableItemStyle
lacks some important properties you absolutely need, you can define your own style class.
A common mistake that developers sometimes make is styling a child control at the wrong timefor example, immediately after creation. I recommend that you use a sort of delayed styling when it comes to rendering constituent controls. When is the latest time to style a child element? When the parent control gets to render.
Here's why you now need to override the Render
protected override void Render(
// Style controls before rendering
// Generate markup
The implementation of the Render
method is straightforward except for the call to an internal method that prepares the control for rendering. The code snippet below is excerpted from the method PrepareControlHierarchyForRendering
. It shows how to apply global settings to the control as a wholeborder, font, colorsand how to style a particular elementthe title.
// Style the control's body
Table t = (Table) Controls;
// Style the title's cell
method imports all visual settings defined through the property grid of Visual Studio .NET.
|Figure 2: Editing the TitleStyle property.|
When you implement style properties, it is essential that you add the following attributes to the property's declaration.
In particular, the PersistenceMode
attribute indicates that the style will be serialized in the ASPX page markup as an inner tag named after the property. This is exactly what happens with the style properties of built-in DataGrid and DataList controls. Figure 2
shows the property grid of the BarChart control when the user is editing the TitleStyle
At this point, the BarChart control is all set and you can focus on the tricks needed to make it effectively work in a host page.