A Crash Course on Custom ASP.NET Data-bound Controls : Page 6

Data-bound controls require a data source property and a set of string properties that link to particular columns of the data source. In addition, they need an Items collection property to track all the building blocks of the control's user interface. Finally, a well-done data-bound control supports styles and custom events.

by Dino Esposito

Aug 19, 2005

Page 6 of 7

Getting Data Source Elements
The CreateControlHierarchy 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 methoda protected overridable method defined on the root Control class.

protected override void CreateChildControls()
{
// Clears all child controls
Controls.Clear();
// If the control is being redrawn because
// of a postback, restore from the ViewState
if (ViewState[ViewStateItemCount] != null)
CreateControlHierarchy(false);
}

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, CreateControlHierarchy 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 ViewStatetypically, 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.

The 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 timefor 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.

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 wholeborder, font, colorsand how to style a particular elementthe title.

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 property.

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.