More on Dynamic Data

Building Field Template Controls

From the Source

LANGUAGES: VB.NET

ASP.NET VERSIONS: 3.5

 

More on Dynamic Data

Building Field Template Controls

 

By Marcin Dobosz and Scott Hunter

 

ASP.NET Dynamic Data is a new feature that ships with the .NET Framework version 3.5 Service Pack 1 (SP1). Dynamic Data allows you to rapidly build a data-driven Web site with full support for create-read-update-delete (CRUD) operations. It also supports data validation based on the database schema, which requires you to write only minimal code. Dynamic Data works on top of the LINQ-to-SQL and ADO.NET Entity Framework object-relational mapping (ORM) technologies, and it can be extended to work with other frameworks. It relies on templates, conventions, and metadata to deliver highly functional, yet easily customizable Web sites.

 

We first wrote about Dynamic Data in An Introduction to Dynamic Data. In this follow-up article, we provide information about how to build field templates to customize the UI for displaying and editing data for specific data types. Our example shows how to use the SliderExtender control from the ASP.NET AJAX Control Toolkit in a field template. (For more information about the AJAX Control Toolkit, and to download it, see the ASP.NET Control Toolkit page on the ASP.NET Web site at http://www.asp.net/ajax/ajaxcontroltoolkit/.)

 

Introduction to Field Templates

Data-bound controls such as the GridView and DetailsView controls can automatically generate UI for displaying and editing data, based on the type of data to which they are bound. (This is the behavior that you get when you set the AutoGenerateColumns or AutoGenerateRows properties to true.) However, this is an all-or-nothing option if you want to modify the UI or behavior of even a single column (for example, by adding styles or validators), you must declare data control fields for all columns. Even then, the automatically generated controls do not offer any built-in validation support. Thus, using the GridView and DetailsView controls to write a data-bound page with customized display or edit behavior requires you to define individual columns or rows that include ASP.NET controls, then to add hard-coded validation rules and error messages. This results in large and hard-to-maintain pages that often have significant amounts of duplicated or very similar code. It also makes it difficult to separate the data model (the business layer) from the presentation layer.

 

Dynamic Data solves these problems by introducing field templates. A field template is a user control that is responsible for rendering a single data-bound field. As with user controls in general, field templates can contain any number of controls to manage UI, such as TextBox, DropDownList, and RangeValidator controls. Dynamic Data project templates provide a number of field templates out of the box that create UI for displaying and editing common data types, such as Boolean, integer, and text, as well as foreign-key relation columns. Each field template can have up to three variants, which are used depending on the mode that the data control is in: read-only, edit, or insert. The variants of the field templates are identified by a naming convention. The table in Figure 1 describes each variant.

 

Field Template Name Pattern

Mode

Behavior

FieldTemplate.ascx

Read-only

Displays the field in non-editing scenarios.

FieldTemplate_Edit.ascx

Edit

Displays the field for editing scenarios. This template should contain validation controls.

FieldTemplate_Insert.ascx

Insert

Optional variant of the field template for insert scenarios. The template should contain validation controls. If this variant is not found, the edit-mode variant will be used.

Figure 1: Variants of the field templates.

 

At run time, Dynamic Data picks the field template for a given column type and given mode from the available field templates. For example, a string column will be displayed using the Text.ascx template in display (read-only) mode and the Text_Edit.ascx template in edit mode. If a particular variant of a field template does not exist in the project, Dynamic Data will try to choose the most appropriate fallback. For example, the default Dynamic Data project template contains an Integer_Edit.ascx field template, but it does not contain an Integer.ascx template. Therefore, Dynamic Data falls back to the Text.ascx template to render UI for integers in read-only mode.

 

By default, field templates are located in the \DynamicData\FieldTemplates directory of a Dynamic Data project. As the page developer, you can modify the default templates to customize how data types are represented in the UI. You also can create your own field templates, then provide hints that tell Dynamic Data how to map a data field in the data model to your field template. In addition, the logic for how Dynamic Data maps data fields to field templates is fully customizable.

 

DynamicField and DynamicControl Classes

You can use field templates in the auto-generate mode of properly configured GridView and DetailsView controls. To do this, place a DynamicDataManager control (a new control that ships as part of Dynamic Data) on the page and call its RegisterControl method in the page s Init event. This configures the GridView or DetailsView to work with Dynamic Data. Figure 2 shows the markup for a DynamicDataManager control and a GridView control. Figure 3 shows the Page_Init handler where the GridView control is registered with the DynamicDataManager control.

 

Figure 2: Markup for DynamicDataManager and GridView controls.

 

Protected Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs)

   DynamicDataManager1.RegisterControl(GridView1)

End Sub

Figure 3: The Page_Init handler where the GridView control is registered with the DynamicDataManager control.

 

In situations where you need to specify the precise ordering or layout of the data-bound control s fields, you can use a new type of data control field named DynamicField. The DynamicField acts as a host that automatically chooses the right field template control for rendering a field. The new DynamicControl control behaves the same way as the DynamicField class, but DynamicControl can be used in data controls that use templates to define UI. This includes templates in the FormView and ListView controls, and TemplateField instances in GridView or DetailsView controls.

 

Building a Custom Field Template

The example in this section illustrates how to build a custom field template for editing integer values. It uses the SliderExtender control from the ASP.NET AJAX Control Toolkit to provide a custom UI for setting the integer value. When a page in a Dynamic Data Web site uses this field template, the result might look something like Figure 4.

 


Figure 4: A custom field template.

 

To be able to use the AJAX Control Toolkit, you must add the AjaxControlToolkit.dll to the project. For a Web Site project, you can create a Bin directory and copy the file into it. For a Web Application project, use the Add Reference dialog box to add the DLL. You ll also need to modify the web.config file by adding the tag-mapping section in the section, as shown in Figure 5. This change lets you reference the controls in the AJAX Control Toolkit by using the ajaxToolkit: prefix.

 

   assembly="AjaxControlToolkit"

   tagPrefix="ajaxToolkit"/>

Figure 5: Add tag-mapping.

 

To build a new field template, right-click the \DynamicData\FieldTemplates\ directory, then click Add New Item. Select Dynamic Data Field, then in the Name box, enter IntegerSlider.ascx. Click Add. This creates the IntegerSlider.ascx and IntegerSlider_Edit.ascx field templates, as well as the associated code-behind files. These files contain default versions of the read-only and edit field templates, along with simple display and edit logic. They are very similar to the Text.ascx and Text_Edit.ascx field templates. For this example, you need only a custom edit field template (that is, you do not need a read-only version of the template). Therefore, delete the IntegerSlider.ascx file from the project.

 

Next, open the IntegerSlider_Edit.ascx and IntegerSlider_Edit.ascx.vb files and replace the default code with the code shown in Figures 6 and 7, respectively.

 

<%@ Control Language="C#" AutoEventWireup="true"

  CodeFile="IntegerSlider_Edit.ascx.vb"

  Inherits="IntegerSlider_EditField" %>

   Text='<%# FieldValueEditString %>'

   TargetControlID="TextBox1"

   BoundControlID="Label1" />

   ControlToValidate="TextBox1"

   Display="Dynamic" />

Figure 6: Open the IntegerSlider_Edit.ascx file and replace the default code.

 

Partial Class DynamicData_FieldTemplates_IntegerSlider_EditField

   Inherits System.Web.DynamicData.FieldTemplateUserControl

   Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)

       Dim metadata = MetadataAttributes.OfType(Of System.ComponentModel.DataAnnotations.RangeAttribute).FirstOrDefault()

       If Not metadata Is Nothing Then

           SliderExtender1.Minimum = metadata.Minimum

           SliderExtender1.Maximum = metadata.Maximum

       End If

       TextBox1.ToolTip = Column.Description

       SetUpValidator(DynamicValidator1)

   End Sub

   Protected Overrides Sub ExtractValues(ByVal dictionary As

           IOrderedDictionary)

       dictionary(Column.Name) = ConvertEditedValue(TextBox1.Text)

   End Sub

   Public Overrides ReadOnly Property DataControl() As Control

       Get

           Return TextBox1

       End Get

   End Property

End Class

Figure 7: Open the IntegerSlider_Edit.ascx.vb file and replace the default code.

 

Field templates must derive from the FieldTemplateUserControl class. This parent class provides a number of helper properties and methods that perform work that is common to all field templates. The most important of these members is the Column property, which contains information about the column with which this field template is associated. The property provides information about the column s metadata (that is, information about the column in the data model) and provides access to the Dynamic Data abstraction of the entire data model.

 

The IntegerSlider_Edit.ascx markup (see Figure 6) is simple. The TextBox1 control is the main data control and contains the value that will be used for the data field on postback. Label1 is an auxiliary control that simply displays the current value of the data field as the user interacts with the slider. SliderExtender1 is the component from the AJAX Control Toolkit that turns TextBox1 into a slider. It is associated with TextBox1 and Label1 via their IDs.

 

The only unfamiliar control is the DynamicValidator control. This is a control specific to Dynamic Data that catches any validation errors that might be thrown by the data model, then displays error messages in the UI. For example, a LINQ-to-SQL model enables you to add custom validation logic using the partial extension method mechanism, as illustrated later in this article. The validation logic can throw a ValidationException error if a property or object fails validation. When the user submits invalid data, the DynamicValidator control catches the validation exception and displays its own error message to the user.

 

Field templates are designed to behave like any other data-bound control, and they therefore support ordinary data-binding syntax to populate values in the controls. The base FieldTemplateUserControl class provides the FieldValue property to retrieve the raw value object. The FieldValueString and FieldValueEditString properties return formatted and HTML-encoded strings for display and edit purposes, respectively. In addition, the Row property can be used to retrieve the entire data row.

 

The code-behind file for the field template contains initialization and data-binding logic. The IntegerSlider_Edit.ascx.vb example (see Figure 7) illustrates how the slider s minimum and maximum allowed values are specified based on metadata about the range information that is derived from the model. The SetUpValidator method is used to configure all standard ASP.NET validators (such as RequiredValidator) as well as DynamicValidator controls with values appropriate to the data field that the template is being used to display. This includes initializing default error messages and other parameters based on the data model s metadata.

 

Because the IntegerSlider template is an edit template, during postback you must get the value that the user has entered. To do this, override the ExtractValues method defined in the IBindableControl interface that is implemented by the FieldTemplateUserControl class. The ExtractValues method gets the modified data and populates a dictionary with the new values. This dictionary will later be passed to a data source control that will in turn perform the appropriate update operation. The example field template also overrides the DataControl property, which can be used in pages that contain DynamicField or DynamicControl controls to obtain a reference to the actual control that is responsible for displaying the data. For example, this can be used to associate a Label control declared on a page with the instance of the data control (such as a TextBox) that is declared in the field template.

 

Annotating the Data Model with Metadata

The IntegerSlider_Edit.ascx name does not match the naming convention used by Dynamic Data to choose the appropriate template by default, when Dynamic Data displays editing UI for integer data, it will look for the field template named Integer_Edit.ascx. To get Dynamic Data to use the custom IntegerSlider_Edit.ascx template, you must add metadata to the data model that maps a specific data column to your new field template.

 

In Dynamic Data, you add metadata to the data model in the form of an associated metadata class. Figure 8 illustrates how you apply metadata for this example. The code assumes that you have a data model class named Widget that has properties named LowRange and HighRange, and that you want to use the IntegerSlider_Edit.ascx field template to edit the data in this class.

 

_

Partial Public Class Widget

End Class

Public Class WidgetMetadata

   Public ReadOnly Property Id() As Object

       Get

           Return Nothing

       End Get

   End Property

   Public ReadOnly Property Name() As Object

       Get

           Return Nothing

       End Get

   End Property

    _

    _

   Public ReadOnly Property LowRange() As Object

       Get

           Return Nothing

       End Get

   End Property

    _

    _

   Public ReadOnly Property HighRange() As Object

       Get

           Return Nothing

       End Get

   End Property

End Class

Figure 8: How to apply metadata.

 

The primary purpose of the Widget partial class is to provide a place to apply attributes that extend the data model; therefore, it contains no actual logic. However, its name must match the name of the data-model type you want to extend. The WidgetMetadata class in turn contains the actual logic for extending the data-model type. To extend individual data columns, you create properties in the metadata class that match the data column names.

 

The MetadataTypeAttribute applied to the Widget partial class specifies the type to use as the metadata class (here, WidgetMetadata class). The attributes applied to the properties of the metadata type are treated by Dynamic Data as if they were applied directly to matching properties of the actual data-model type. In this example, the LowRange and HighRange properties of the Widget class each have the RangeAttribute and UIHintAttribute attributes applied.

 

UIHintAttribute overrides the default field-template mapping. In this case, Dynamic Data will try to load the IntegerSlider_Edit.ascx control when a field template is requested in order to produce UI for editing the LowRange or HighRange column values. RangeAttribute declares the range of values for a specific column. It is used by the field template initialization method to set the bounds for the SliderExtender control. RangeAttribute inherits from ValidationAttribute. The ValidationAttribute class encapsulates validation checks. Therefore, RangeAttribute can perform its own validation checks. This ensures that even if a client is able to bypass the range limitations set by the slider UI and submit an invalid value, the submitted value will be validated on the server by RangeAttribute and result in an error. These errors will then be captured and displayed by the DynamicValidator control.

 

Conclusion

Field templates are a powerful feature that provide a compelling reason to use Dynamic Data, even in existing ASP.NET Web applications. The ability to extend the data model, combined with centralized field templates, significantly reduces the need for code (and maintenance) in creating data-bound UI. By creating a suite of field templates that define the UI for your needs, you can get a sophisticated, highly functional Web application UI up and running in no time, and with very little coding.

 

Source code accompanying this article is available for download.

 

Marcin Dobosz is a developer on the ASP.NET team. He currently is working on the Dynamic Data feature. You can find him online at http://blogs.msdn.com/MarcinOn/.

 

Scott Hunter is a program manager on the ASP.NET team. He currently is working on the Dynamic Data feature. Scott has been working in the industry for more than 20 years and has spent the past seven years building Web applications on the ASP.NET platform. You can find him online at http://blogs.msdn.com/scothu/.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish