|
|||||||||
|
Custom
Template Classes
The template technique seen so far is great if you want to dynamically apply the same template to all the rows of a Repeater, DataList or DataGrid, but there yet one more situation you may face. Say for example that you want to use a red foreground color for employees that have a salary greater than a certain amount, and instead use green for employees that make less that another amount. Or that you want to render with different background colors the male, female, and gender-neutral employees, according to their title of courtesy. Or again, you may want to hide some information only for employees that explicitly required this (the e-mail or mailing address, for example), but not for everybody.
Some of these row-by-row customizations, such as showing/hiding certain data, can be done by binding the Visible property of a Label to an expression. Others, regarding the visual customization of the item’s layout and style or the data being shown, can be done by handling the control’s ItemCreated and ItemDataBound events. However, if you need the same customized template for more than one control, possibly in different pages, you’ll end up repeating the same template definition and the same code-behind for its customization over and over again, in many places. This is not the best for maintainability and code-reuse of course. In these cases, you can create a class that implements the ITemplate interface, and that programmatically creates all the controls for the template column or item, and takes care of binding the required data to the proper controls. In practice, it does by code everything you would declare in the ASPX file and in the code-behind. Then, you can create an instance of this class and associate it to the Repeater’s, DataList’s or DataGrid’s templates, as we did before with the templates loaded from file. This is a great option, because in a single class you can have everything is required for your row-by-row custom output, and you achieve a great code reuse because you’ll be able to use the class from everywhere in your project, or in any other project if you compile the class in its own redistributable Class Library assembly. As an example, we’re going to see how to render the employees with different background colors, according to their title of courtesy. We declare a class that implements ITemplate, add any custom property (I use public fields in the example below, as I don’t have to validate the value, but the concept it’s the same) and a constructor that takes in input the values to initialize these properties:
The ITemplate interface has a single method to implement, InstantiateIn, called when the container’s item is being created, and where we must instantiate the controls that will show the data. In this example we need three labels, for the employee’s first and last names, and the title of courtesy. However, we first create a panels that covers the whole container’s item’s size, and then add the labels inside it. We use a container panel control so that’s easier to set the item’s background color. So, the labels are added to the panel’s Controls collection, and the panel itself is added to the container control’s Controls collection. Here’s the code for this method:
At this point we’ve only declared the controls for the template, but haven’t yet specified what they should show. To bind the data to these controls, we must react to their DataBinding events, raised when a row in the Repeater / DataList / DataGrid, and so the inner controls in its templates, are being bound to a data item. If you look again to the above, you’ll see that the Panel control was declared at class level, with the WithEvents keyword, so that’s easy to handle its events. The next method we have to write is actually an handler for the panel’s DataBinding event, where we get a reference to the container’s data item, extract the data we want (the first and last names, and the title of courtesy), and show it in the three labels created in the InstantiateIn method. Let’s first see the complete code:
First of all, as we earlier did in the template files, we must cast the generic panel’s container to the right type (DataListItem, for example), so that we can access its properties, such as DataItem. However, while the template files were tailor-made for a specific template control, we want to make this class working with either the Repeater, the DataList or DataGrid. With the template files this wasn’t important because in case we wanted to switch from a DataList to a DataGrid we had just to make a little modification to a couple of text files. In this case however things would be much more difficult, because we’d also have to recompile the codeand this could be even impossible if we don’t have the source code but are referencing the class from a compiled assembly developed by someone else. Therefore, you’d likely want to write a single class that can work with any of these three controls. For this reason, we check the type of the container with the TypeOf function, cast the container to the proper type and get an Object reference from the DataItem property, that represents the data item being bound to this item. Before being able to read the values we need from the retrieved data item, we must follow a similar process though, because the data item can be of type DbDataRecord or DataRowView, according to whether the container Repeater / DataList or DataGrid’s DataSource is a DataReader or a DataTable/DataView, respectively. In the code above you see that we use again the TypeOf function to know the right type for the cast, do the cast and can finally read the wanted values and save them to local variables. We’re near the end. At this point, we use the retrieved TitleOfCourtesy value to decide which background color we have to use to render the employee, and use it for the panel’s BackColor property. Finally, we get the references to the inner Label controls we added to the panel, by casting from the general Control returned by the panel’s Controls collection to Label, and then assigning their Text properties with the values read from the data item.
|
|||||||||
|