Chapter 3. Field Templates

In This Chapter

Read-Only Templates

Field Value Display Format

Edit and Insert Mode Templates

Field Value Edit Format

Changing Existing Field Template

Data Binding

Creating a New Field Template

Field Template Lookup Rules

Built-in Field Templates

Enterprise applications deal with employees, managers, emergency contacts, prospects, customers, suppliers, and vendors—in other words, people and organizations, who all have names, addresses, and phone numbers. Implementing data entry logic for these attributes is repetitive, and for years, the ASP.NET developers have been developing user controls to reduce the code duplication. It is common to see user controls with text boxes and validators for entering street, city, state, and postal code in many web applications today.

Although they are a great mechanism for reusing presentation and validation logic, user controls require a certain amount of plumbing before they can be used on a web page. At the very minimum, user controls must be registered, and because even the simplest controls need to provide slightly varying functionality in different contexts, they also usually have one or more properties that need to be configured. As the user controls get more and more granular, the amount of plumbing work required to apply them increases. It quickly reaches the point of diminishing returns, and developers usually stop short of implementing user controls for the individual data entry fields.

Field template is a special type of ASP.NET user control that encapsulates presentation and validation logic for a single field. Unlike the traditional user controls, field templates do not require registration. Instead, a simple DynamicControl or a DynamicField placed on a web page automatically loads and configures an appropriate field template based the column name and metadata.

Metadata information, readily available in Dynamic Data web applications, dramatically lowers the amount of plumbing code developers have to write when working with user controls, enables effective use of smaller user controls, and takes code reuse to an unprecedented new level.

Read-Only Templates

By convention, field templates are located in the DynamicDataFieldTemplates folder of the Dynamic Data web application projects and websites. A single instance of a field template provides user interface for one particular field value. Consider Listing 3.1, which shows markup file of the DateTime field template.

Listing 3.1. DateTime Field Template (Markup)


<%@ Control Language="C#" CodeBehind="DateTime.ascx.cs"
  Inherits="WebApplication.DynamicData.FieldTemplates.DateTimeField" %>

<asp:Literal runat="server" ID="literal" Text="<%# FieldValueString %>" />


This is a read-only field template, the simplest type of field template. It relies on ASP.NET data binding syntax <%# %> to display the field value in a single Literal control. Listing 3.2 shows the code-behind of the DateTime field template. You can see that it inherits from the FieldTemplateUserControl, a special base class provided for field templates by Dynamic Data. This class defines the FieldValueString property to which the Literal control is bound.

Listing 3.2. DateTime Field Template (Code-behind)


using System.Web.DynamicData;
using System.Web.UI;

namespace WebApplication.DynamicData.FieldTemplates
{
  public partial class DateTimeField : FieldTemplateUserControl
  {
    public override Control DataControl
    {
      get { return this.literal; }
    }
  }
}


Code-behind files perform most of the work required to make the generated web pages dynamic. In this simplest example, the template overrides the DataControl property defined by the base class. Entity templates (see Chapter 4, “Entity Templates”) use this property when dynamically generating entity forms, to associate each field template with a matching Label control.

Field Value Display Format

In addition to the FieldValueString property, the FieldTemplateUserControl class also provides another property called FieldValue, which returns the raw value object. At a cursory glance, the FieldValue property could be used to bind the Literal control as well. However, it is important to use the FieldValueString property as it automatically takes into account additional display format properties when converting the raw field value to a string:

DataFormatString specifies a .NET format string that will be passed to the String.Format method to convert the field value to a display string.

NullDisplayText specifies a replacement string that will be used when the raw field value is null.

ConvertEmptyStringToNull is a Boolean value that determines whether an empty string value should treated as null and if the NullDisplayText will be used as a replacement for empty strings as well as null values. This property is true by default.

HtmlEncode is a Boolean value that determines whether any special HTML symbols in the raw field value, such as '<' or '>', will be encoded using escape sequences, such as &lt; and &gt;. This property is true by default.

Display format properties can be specified in the data model by applying the DataTypeAttribute or the DisplayFormatAttribute to a particular column, as shown in Listing 3.3. The DisplayFormatAttribute, applied to the OrderDate column, specifies a long date {0:D} format string. The DataTypeAttribute, applied to the RequiredDate column, does not have its own DataFormatString property. Instead, it offers the DisplayFormat property, which gets a default DisplayFormatAttribute generated, based on the specified data type. For DataType.Date, the default data format string will be a short date {0:d}.

Listing 3.3. Specifying Display Format Using Data Annotations


using System.ComponentModel.DataAnnotations;

namespace DataModel
{
  [MetadataType (typeof(Order.Metadata))]
  partial class Order
  {
    public class Metadata
    {
      [DisplayFormat(DataFormatString = "{0:D}")]
      public object OrderDate;

      [DataType(DataType.Date)]
      public object RequiredDate;
    }
  }
}


Display format properties can be also specified in page markup by setting the corresponding properties of the DynamicControl or DynamicField classes, similar to the properties of the “non-dynamic” BoundField. Listing 3.4 shows an example where a DynamicField is used in a GridView control and specifies a custom date format string {0:MM/dd/yy} for the ShippedDate column.

Listing 3.4. Specifying Data Format Using DynamicField


<%@ Page Language="C#"
  MasterPageFile="~/Site.master" CodeBehind="SamplePage.aspx.cs"
  Inherits="WebApplication.Samples.Ch01.DataFormatString.SamplePage" %>

<asp:Content ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
  <asp:GridView ID="gridView" runat="server" DataSourceID="dataSource"
    AutoGenerateColumns="false" AllowPaging="true">
    <columns>
      <asp:DynamicField DataField="OrderDate" />
      <asp:DynamicField DataField="RequiredDate" />
      <asp:DynamicField DataField="ShippedDate" DataFormatString="{0:MM/dd/yy}" />
    </columns>
  </asp:GridView>
  <asp:EntityDataSource ID="dataSource" runat="server"
    ConnectionString="name=NorthwindEntities"
    DefaultContainerName="NorthwindEntities" EntitySetName="Orders" />
</asp:Content>


Figure 3.1 shows the web page generated by this code. As you can see, the OrderDate values use the long format specified in the DisplayFormatAttribute in the model; the RequiredDate values use the short format provided by the DataTypeAttribute; and the ShippedDate values use the custom format specified in the page markup.

Image

Figure 3.1. GridView with DataType and DisplayFormat attributes applied.

Inside of the field templates, the display format properties are available via the FormattingOptions property inherited from the FieldTemplateUserControl. The base class automatically initializes them based on the formatting options of the host—DynamicControl or DynamicField.

As you might expect, a fair amount of logic is involved in converting the raw field value to the final display string. By using the FieldValueString property of the FieldTemplateUserControl class, field templates ensure consistent behavior that offers application developers great flexibility in defining the presentation aspects of their data. The DataTypeAttribute allows specifying default display properties for a column in the data model based on its data type. The DisplayFormatAttribute allows fine-tuning it with the standard or custom format strings. Finally, the DynamicControl and DynamicField controls allow tailoring the display of column values for a specific page in a web application.

Edit and Insert Mode Templates

In addition to the read-only field templates, Dynamic Data has Edit and Insert field templates. Unlike the Read-Only templates, where the field value is simply displayed on the page, the Edit templates allow the user to modify it using a data entry control, such as a TextBox. By convention, Dynamic Data distinguishes Edit and Insert templates by the _Edit and _Insert they have at the end of their file names, respectively. The Insert templates are a special case of Edit templates, used for editing field values of rows that have not been saved to the database. However, most Edit mode field templates can be used in Insert mode as well.

The Edit field templates are significantly more complex than their read-only counterparts. Consider Listing 3.5, which shows the Edit version of the DateTime field template.

Listing 3.5. DateTime_Edit Field Template (Markup)


<%@ Control Language="C#" CodeBehind="DateTime_Edit.ascx.cs"
  Inherits="WebApplication.DynamicData.FieldTemplates.DateTime_EditField" %>

<asp:TextBox ID="textBox" runat="server" Text='<%# FieldValueEditString %>'
  Columns="20" />

<asp:RequiredFieldValidator runat="server" ID="requiredFieldValidator"
  ControlToValidate="textBox" Enabled="false" />
<asp:RegularExpressionValidator runat="server" ID="regularExpressionValidator"
  ControlToValidate="textBox" Enabled="false" />
<asp:DynamicValidator runat="server" ID="dynamicValidator"
  ControlToValidate="textBox" />
<asp:CustomValidator runat="server" ID="dateValidator" ControlToValidate="textBox"
  EnableClientScript="false" Enabled="false"
  OnServerValidate="DateValidator_ServerValidate" />


In addition to the data entry control, the edit field templates typically have one or more validation controls. The DateTime_Edit template includes a RequiredFieldValidator, a RegularExpressionValidator, a DynamicValidator, and a CustomValidator control. Notice that with the exception of the DynamicValidator, these controls are not enabled by default. They are configured dynamically by the Page_Load event handler defined in the code-behind file shown in Listing 3.6.

Each validator control is configured by a call to the SetUpValidator method of the FieldTemplateUserControl base class. This method enables and configures the validator if the column metadata contains an appropriate data annotation attribute. In particular, the RequiredFieldValidator will be enabled when the column is marked with a RequiredAttribute that does not allow empty strings, and the RegularExpressionValidator will be enabled when the column is marked with a RegularExpressionAttribute. In addition to enabling the validator, the SetUpValidator method also assigns its ErrorMessage and ToolTip properties with an error message either explicitly specified in the data annotation attribute or generated based on the column’s display name.

DynamicValidator is a special validation control provided by Dynamic Data. It ensures all validation attributes applied to the column are invoked to verify its value is correct. This andincludes not only the well-known RequiredAttribute, RangeAttribute, and CustomValidationAttribute, but also all other descendants of the ValidationAttribute that may be applied to the column and are not covered by a specific ASP.NET validator control in this field template.

The CustomValidator control in this field template performs the job you would normally expect the DataTypeAttribute to do. Even though DataTypeAttribute inherits from the ValidationAttribute class, it does not actually perform any validation. Its IsValid method always returns true, which is why the DateTime_Edit template uses the CustomValidator control to ensure that the value entered by the user matches the type specified by the DataTypeAttribute. The SetUpCustomValidator method enables the validator if the column was marked with a DataTypeAttribute and the DateValidator_ServerValidate method performs the actual validation.

Listing 3.6. DateTime_Edit Field Template (Code-Behind)


using System;
using System.Collections.Specialized;
using System.ComponentModel.DataAnnotations;
using System.Web;
using System.Web.DynamicData;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication.DynamicData.FieldTemplates
{
  public partial class DateTime_EditField : FieldTemplateUserControl
  {
    private static DataTypeAttribute DefaultDateAttribute =
      new DataTypeAttribute(DataType.DateTime);

    public override Control DataControl
    {
      get { return this.textBox; }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
      this.textBox.ToolTip = this.Column.Description;

      this.SetUpValidator(this.requiredFieldValidator);
      this.SetUpValidator(this.regularExpressionValidator);
      this.SetUpValidator(this.dynamicValidator);
      this.SetUpCustomValidator(this.dateValidator);
    }

    protected override void ExtractValues(IOrderedDictionary dictionary)
    {
      dictionary[Column.Name] = this.ConvertEditedValue(this.textBox.Text);
    }
    protected void DateValidator_ServerValidate(object source,
      ServerValidateEventArgs args)
    {
      DateTime dummyResult;
      args.IsValid = DateTime.TryParse(args.Value, out dummyResult);
    }

    private void SetUpCustomValidator(CustomValidator validator)
    {
      if (this.Column.DataTypeAttribute != null)
      {
        switch (this.Column.DataTypeAttribute.DataType)
        {
          case DataType.Date:
          case DataType.DateTime:
          case DataType.Time:
            this.EnableCustomValidator(validator, this.Column.DataTypeAttribute);
            break;
        }
      }
      else if (this.Column.ColumnType.Equals(typeof(DateTime)))
      {
        this.EnableCustomValidator(validator, DefaultDateAttribute);
      }
    }

    private void EnableCustomValidator(CustomValidator validator,
      DataTypeAttribute attribute)
    {
      validator.Enabled = true;
      validator.ErrorMessage = HttpUtility.HtmlEncode(
        attribute.FormatErrorMessage(this.Column.DisplayName));
    }
  }
}


Field Value Edit Format

You might have noticed that the DateTime_Edit template uses the FieldValueEditString property of the FieldTemplateUserControl base class. This property is similar to the FieldValueString property discussed earlier in that it respects the FormattingOptions when converting the raw column value to a display string. However, it was specifically designed for use in the Edit mode templates, and an additional property is used to control its behavior.

ApplyFormatInEditMode is a Boolean value that determines whether the DataFormatString, NullDisplayText, ConvertEmptyStringToNull, and HtmlEncode display format properties will be used in Edit mode. This property is false by default.

Similar to using the FieldValueString property when implementing Read-only field templates, it is also important to rely on the FieldValueEditString property as much as possible when implementing the Edit and Insert mode templates. This helps the field templates to behave consistently and allow the application developers to change presentation aspects of column values using metadata attributes as well as explicit configuration in page markup.

Changing Existing Field Template

Dynamic Data uses the same field template for all matching columns in the model. The DateTime_Edit field template is automatically used for all columns of type DateTime in the Northwind data model, including OrderDate, RequiredDate, and ShippedDate columns of the Order table as well as BirthDate and HireDate columns of the Employee table. By changing definition of the field template, you affect all web pages where it is used. Figure 3.2 shows how the experience of entering date values can be improved by allowing the users to select a date from a calendar drop-down.

Image

Figure 3.2. Modified DateTime field template with calendar drop-down.

The modified field template, DateTime_Edit.ascx, is shown in Listing 3.7. This example uses the CalendarExtender control from the AJAX Control Toolkit, but you can use any other ASP.NET control from your favorite component vendor. The CalendarExtender is associated with the TextBox by specifying its TagetControlID property. Using the PopupButtonID property, it is also associated with an ImageButton that users can click to display the calendar drop-down.


Note

The AJAX (Asynchronous JavaScript and XML) Control Toolkit is an extension of the ASP.NET framework developed by Microsoft to enhance client-side behavior of the standard WebForms controls. It is an open source project hosted on CodePlex and available for download at http://AjaxControlToolkit.CodePlex.com.

The AJAX Control Toolkit comes in a ZIP archive that you need to extract to a directory on your hard drive. Before you can begin using AJAX controls, you need to add the downloaded AjaxControlToolkit.dll as a reference to your web application project in Visual Studio.


Listing 3.7. Extended DateTime_Edit Field Template (Markup)


<%@ Control Language="C#" CodeBehind="DateTime_Edit.ascx.cs"
  Inherits="WebApplication.DynamicData.FieldTemplates.DateTime_EditField" %>

<asp:TextBox ID="textBox" runat="server" Text='<%# FieldValueEditString %>'
  Columns="20" />
<asp:ImageButton ID="calendarButton" runat="server"
  ImageUrl="../Content/Images/Calendar.png" />
<ajax:CalendarExtender runat="server" TargetControlID="textBox"
  PopupButtonID="calendarButton" />

<asp:RequiredFieldValidator runat="server" ID="requiredFieldValidator"
  ControlToValidate="textBox" Enabled="false" />
<asp:RegularExpressionValidator runat="server" ID="regularExpressionValidator"
  ControlToValidate="textBox" Enabled="false" />
<asp:DynamicValidator runat="server" ID="dynamicValidator"
  ControlToValidate="textBox" />
<asp:CustomValidator runat="server" ID="dateValidator" ControlToValidate="textBox"
  EnableClientScript="false" Enabled="false"
  OnServerValidate="DateValidator_ServerValidate" />


Notice that this example uses a custom ajax: tag prefix with the CalendarExtender without actually registering it. We could have used the ASP.NET <%@ Register %> directive to register this tag prefix directly in the DateTime_Edit.ascx. However, because the AJAX Control Toolkit is used in other field templates of this sample project, it is better to register it in the Web.config as shown in Listing 3.8. This makes the AJAX controls available in all pages and controls of the web application and helps you avoid having to register the same tag prefix in multiple pages and user controls.

Listing 3.8. Registering AJAX Controls in the Web Configuration File


<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0"/>
    <pages styleSheetTheme="Default">
      <controls>
        <add tagPrefix="ajax" assembly="AjaxControlToolkit"
          namespace="AjaxControlToolkit"/>
      </controls>
    </pages>
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
  <connectionStrings>
    <add name="NorthwindEntities"
      providerName="System.Data.EntityClient"
      connectionString="
        metadata=res://*/Northwind.csdl¦
                 res://*/Northwind.ssdl¦
                 res://*/Northwind.msl;
        provider=System.Data.SqlClient;
        provider connection string=&quot;
          data source=.sqlexpress;
          initial catalog=Northwind;
          integrated security=True;
          multipleactiveresultsets=True&quot;"/>
  </connectionStrings>
</configuration>


Data Binding

Several of the built-in Dynamic Data field templates, including the DateTime and DateTime_Edit templates, rely on data binding to display column value on the page.

<asp:TextBox ID="textBox" runat="server" Text='<%# FieldValueEditString %>' />

In addition, the field template controls themselves are data bound, and several properties of the FieldTemplateUserControl base class rely on the data binding mechanics. These properties can be used safely only from the DataBind method and will throw an InvalidOperationException when used outside of the data binding context, such as during a post-back:

Row provides access to the entity instance the field template is bound to, such as an Order object. In Read-only and Edit modes, it is an equivalent of calling the Page.GetDataItem method. In Insert mode, this property returns a CustomTypeDescriptor object that provides access to default field values extracted by the page template from the page request URL (more on this in Chapter 6, “Page Templates”).

FieldValue returns value of the column property, such as Order.OrderDate. It is an equivalent of calling DataBinder.Eval(Row, Column.Name).

FieldValueString converts the field value to a display string in Read-only mode, using the formatting options specified in the data model or page markup. It is an equivalent of calling FormattingOptions.FormatValue(FieldValue).

FieldValueEditString converts the field value to a string in Edit or Insert mode, using the formatting options specified in the data model or page markup. It is an equivalent of calling FormattingOptions.FormatEditField(FieldValue).

During a post-back, a field template itself does not actually save the new column value back in its Row object. Instead, the FieldTemplateUserControl class implements the IBindableControl interface and relies on the parent FormView, DetailsView, and GridView controls to perform this task. When the parent control is handling an Insert or an Update command, it iterates through the list of its child controls and calls the ExtractValues of each child that implements IBindableControl interface.

protected override void ExtractValues(IOrderedDictionary dictionary)
{
  dictionary[this.Column.Name] =
    this.ConvertEditedValue(this.textBox.Text);
}

The ExtractValues method receives a dictionary object used to store column name and value pairs. The extract from the DateTime_Edit field template just shown is a typical implementation of this method. The ConvertEditedValue method is provided by the FieldTemplateUserControl base class. It can automatically convert the field value to null based on the ConvertEmptyStringToNull and NullDisplayText formatting options.

Notice that by providing the dictionary argument, ExtractValue method allows a field template to return values of other columns or even multiple column values. This capability is important for the foreign key templates used for navigation properties, such as the Customer property of the Order class in the Northwind data model, that need to return values of the corresponding primitive properties, such as CustomerID. Consider Listing 3.9, which shows the markup of the ForeignKey_Edit template.

Listing 3.9. ForeignKey_Edit Field Template (Markup)


<%@ Control Language="C#" CodeBehind="ForeignKey_Edit.ascx.cs"
  Inherits="WebApplication.DynamicData.FieldTemplates.ForeignKey_EditField" %>

<asp:DropDownList ID="dropDownList" runat="server"/>

<asp:RequiredFieldValidator runat="server" ID="requiredFieldValidator"
  ControlToValidate="dropDownList" Enabled="false" />
<asp:DynamicValidator runat="server" ID="dynamicValidator"
  ControlToValidate="dropDownList" />


Notice that the ForeignKey_Edit template uses a DropDownList control, which allows users to select from a list of items created programmatically, in the Page_Load method shown in Listing 3.10. Each ListItem object in the DropDownList represents a single foreign key, with Text property storing value of the display column from the referenced table and Value property storing a comma-separated list of its primary key columns. This code relies on the convenience method, called PopulateListControl, provided by the FieldTemplateUserControl base class, which does all the heavy lifting required to query the referenced table, create the ListItem objects, and add them to the DropDownList.

Listing 3.10. ForeignKey_Edit Field Template (Code-Behind)


using System;
using System.Collections.Specialized;
using System.Web.DynamicData;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication.DynamicData.FieldTemplates
{
  public partial class ForeignKey_EditField : FieldTemplateUserControl
  {
    public override Control DataControl
    {
      get { return this.dropDownList; }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
      if (this.dropDownList.Items.Count == 0)
      {
        if (this.Mode == DataBoundControlMode.Insert ¦¦ !this.Column.IsRequired)
          this.dropDownList.Items.Add(new ListItem("[Not Set]", string.Empty));
        this.PopulateListControl(this.dropDownList);
      }

      this.SetUpValidator(this.requiredFieldValidator);
      this.SetUpValidator(this.dynamicValidator);
    }

    protected override void OnDataBinding(EventArgs e)
    {
      base.OnDataBinding(e);
      string selectedValueString = this.GetSelectedValueString();
      if (this.dropDownList.Items.FindByValue(selectedValueString) != null)
        this.dropDownList.SelectedValue = selectedValueString;
    }
    protected override void ExtractValues(IOrderedDictionary dictionary)
    {
      this.ExtractForeignKey(dictionary, this.dropDownList.SelectedValue);
    }
  }
}


To display the current field value, the ForeignKey_Edit template cannot rely on the FieldValueEditString property because the FieldValue in this case consists of one or more values of the underlying primitive columns. For the Customer column of the Order table, this would mean displaying CustomerID, “ALFKI”, instead of the Customer’s CompanyName, “Alfreds Futterkiste”, which is not very user friendly. Instead, the ForeignKey_Edit template overrides the OnDataBinding method to select the matching item in the DropDownList. It calls the GetSelectedValueString, a convenience method provided by the FieldTemplateUserControl base class. For foreign key columns, this method is equivalent to calling ForeignKeyColumn.GetForeignKeyString(Row) and returns a comma-separated list of values of the primitive columns in the foreign key.

The ForeignKey_Edit template also overrides the ExtractValues method and calls the ExtractForeignKey provided by the FieldTemplateUserControl base class. Given a comma-separated list of column values, this method stores them in the dictionary under the names of the foreign key columns. Under the hood, this method simply calls ForeignKeyColumn.ExtractForeignKey(dictionary, selectedValue).

Creating a New Field Template

The set of field templates provided by Dynamic Data can be extended whenever a special data entry control is needed to handle values of a certain type. For example, the Northwind database uses regular string columns to store phone numbers for customers, employees, suppliers, and shippers. The phone numbers already stored in the database are in a consistent (###)###-#### format; however, Dynamic Data uses the regular Text_Edit field template for these columns, which does not enforce the phone number format. It would be nice to create a field template that would help users enter the phone numbers correctly.

You create a new field template by adding a new user control to the DynamicDataFieldTemplates folder of your project. You can also copy an existing field template that most closely matches the desired functionality. If you do copy an existing field template, remember to change the class name in both markup and code-behind files. In this example, however, we will start from scratch and create a new user control called PhoneNumber_Edit, shown in Listing 3.11.

Listing 3.11. PhoneNumber_Edit Field Template (Markup)


<%@ Control Language="C#" CodeBehind="PhoneNumber_Edit.ascx.cs"
  Inherits="WebApplication.DynamicData.FieldTemplates.PhoneNumberEditField" %>

<asp:TextBox ID="textBox" runat="server" Text='<%# FieldValueEditString %>'/>
<ajax:FilteredTextBoxExtender TargetControlID="textBox" runat="server"
  FilterType="Custom" ValidChars="+()-1234567890" />

<asp:RequiredFieldValidator runat="server" ID="requiredFieldValidator"
  ControlToValidate="textBox" Enabled="false" />
<asp:RegularExpressionValidator runat="server" ID="regularExpressionValidator"
  ControlToValidate="textBox" />
<asp:DynamicValidator runat="server" ID="dynamicValidator"
  ControlToValidate="textBox" />


As you can see, the PhoneNumber_Edit field template is similar to the DateTime template discussed earlier. It has a TextBox control used to enter the phone number, a FilteredTextBoxExtender, another AJAX control used to prevent users from entering symbols that would not be valid in a phone number, as well as several validator controls.

Although having a single DynamicValidator control is sufficient to enforce all validation attributes applied to the column in the data model, this control performs validation only on the server side, which requires a post-back before the error can be reported. Other ASP.NET validation controls, such as the RequiredFieldValidator, are optional, but because they also offer client-side validation logic, it’s best to include them in field templates to provide immediate feedback to the user, and improve the data entry experience.

Listing 3.12 shows the code-behind of the PhoneNumber_Edit field template.

Listing 3.12. PhoneNumber_Edit Field Template (Code-Behind)


using System;
using System.Collections.Specialized;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.DynamicData;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication.DynamicData.FieldTemplates
{
  public partial class PhoneNumberEditField : FieldTemplateUserControl
  {
    public override Control DataControl
    {
      get { return this.textBox; }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
      this.textBox.ToolTip = this.Column.Description;

      this.SetUpValidator(this.requiredFieldValidator);
      this.SetUpValidator(this.dynamicValidator);
      this.SetUpRegexValidator(this.regularExpressionValidator);
    }

    protected override void ExtractValues(IOrderedDictionary dictionary)
    {
      dictionary[this.Column.Name] = this.ConvertEditedValue(this.textBox.Text);
    }

    private void SetUpRegexValidator(RegularExpressionValidator validator)
    {
      RegularExpressionAttribute attribute = this.Column.Attributes
        .OfType<RegularExpressionAttribute>().FirstOrDefault();
      if (attribute == null)
      {
        attribute = new RegularExpressionAttribute(@"(d{3})d{3}-d{4}");
        attribute.ErrorMessage = "The field {0} must be a valid phone number.";
      }

      validator.Enabled = true;
      validator.Text = "*";
      validator.ValidationExpression = attribute.Pattern;
      validator.ErrorMessage = HttpUtility.HtmlEncode(
        attribute.FormatErrorMessage(this.Column.DisplayName));
      validator.ToolTip = validator.ErrorMessage;

      this.IgnoreModelValidationAttribute(attribute.GetType());
    }
  }
}


Most of the phone number validation in the new field template is performed by the standard ASP.NET control, RegularExpressionValidator, which ensures that the value entered by the user matches the regular expression pattern that defines a valid phone number. In addition to the server-side validation based on the .NET implementation of regular expressions in the System.Text.RegularExpressions namespace, it also works on the client side taking advantage of the regular expression functionality in JavaScript.

The RegularExpressionValidator is configured by the SetUpRegexValidator method defined in the code-behind. This method first searches the list of attributes applied to the column in the data model, Column.Attributes, for a RegularExpressionAttribute that might have been supplied by the application developer to indicate the expected phone number pattern. If no such attribute exists, this method creates a default Regular ExpressionAttribute with the pattern, (d{3})d{3}-d{4}, that matches U.S. phone numbers, such as (877)514-9180, with a three-digit area code in parentheses, followed by a seven-digit local number. The default attribute also has a generic error message that says that a column must be a valid phone number.

Having obtained the RegularExpressionAttribute instance, the SetUpRegexValidator method configures the RegularExpressionValidator control consistently with how the SetUpValidator method of the FieldTemplateUserControl base class does it—the Text displayed by the validator itself is always a star symbol; its ErrorMessage is reported through a ValidationSummary control on the page and the ToolTip contains the complete error message.

The last step in setting up the RegularExpressionValidator is to call the IgnoreModel ValidationAttribute method of the FieldTemplateUserControl base class. This allows the DynamicValidator to ignore the RegularExpressionAttribute during its validation because this attribute is already covered by the RegularExpressionValidator. Aside from helping to avoid doing the same validation check twice, this also prevents the regular expression validation error from being reported twice—first by the RegularExpression Validator and then by the DynamicValidator control.

Listing 3.13 shows an example of how the new PhoneNumber_Edit field template can be associated with a column using data annotation attributes.

Listing 3.13. Associating PhoneNumber Template with a Column


using System.ComponentModel.DataAnnotations;

namespace DataModel
{
  [MetadataType(typeof(Employee.Metadata))]
  partial class Employee
  {
    public class Metadata
    {
      [DataType(DataType.Date)]
      public object BirthDate;

      [DataType(DataType.Date)]
      public object HireDate;

      [DataType(DataType.PhoneNumber)]
      [RegularExpression(@"(d{2,3})d{3}-d{4}",
        ErrorMessage = "The Home Phone must be a valid phone number.")]
      public object HomePhone;
    }
  }
}


DataTypeAttribute, applied to the HomePhone column, specifies this string column’s actual data type is PhoneNumber. Dynamic Data uses this information as a hint when looking for a matching field template for this column and chooses the new PhoneNumber_Edit template instead of the default Text_Edit. In this example, RegularExpressionAttribute is also applied to the HomePhone column to provide a pattern that matches not only U.S. phone numbers, which have three-digit area codes, but also UK numbers, which might have two-digit area codes.

Figure 3.3 shows the Employee Edit page after the implementation of the PhoneNumber_Edit field template has been completed. Although you cannot tell from this screenshot, thanks to the FilteredTextBoxExtender, you cannot type any alphabetical symbols in the phone number text box. The pattern validation is performed on the client side as soon as you tab out of the text box, such as in this case, where one digit was removed from an otherwise valid UK phone number.

Image

Figure 3.3. Employee Edit page with the New PhoneNumber_Edit field template.

Field Template Lookup Rules

Dynamic Data tries to find the most specific template that matches the field based on the column type and control mode. If such a field template does not exist, Dynamic Data will gradually relax the matching rules until it finds the best possible match among the field templates in the project.

Data Annotations

Consider the RequiredDate column of the Order table used in Listing 3.3 earlier in this chapter. If the developer specifies the exact template name by applying the UIHintAttribute as shown in Listing 3.14, Dynamic Data first checks to see if a template with the specified name, MyDate.ascx, exists. If this template does not exist, Dynamic Data then checks if a DataTypeAttribute is applied to the column and tries using the specified DataType value as the template name. In this example, it checks to see if a field template called Date.ascx exists.

Listing 3.14. Data Annotations That Affect Field Template Lookup


using System.ComponentModel.DataAnnotations;

namespace DataModel
{
  [MetadataType(typeof(Order.Metadata))]
  partial class Order
  {
    public class Metadata
    {
      [UIHint("MyDate")]
      [DataType(DataType.Date)]
      public object RequiredDate;
    }
  }
}


Type Names

If the column has no data annotation attributes, Dynamic Data then tries to find a matching template based on the name of its type. First, it looks for a template whose name matches the full name of the type, including the namespace where the type is defined. In the example of RequiredDate, when looking for a template for a column of DateTime type, it checks to see if a template called System.DateTime.ascx exists. If not, Dynamic Data then tries the short type name, without the namespace, and finally chooses the template called DateTime.ascx provided by Dynamic Data out of the box.

Type Aliases

Dynamic Data allows template names to use special aliases instead of actual type names for two built-in .NET types, Int32 and String. When looking for a field template for a column of type String, Dynamic Data considers the template called Text.ascx to be a match. In the Northwind data model, this means that the Text.ascx template will be used for the ProductName column of the Product table. Likewise, when looking for a template for an Int32 column, Dynamic Data considers Integer.ascx to be a match as well. Table 3.1 shows the built-in type aliases at a glance.

Table 3.1. Type Name Aliases

Image

Type aliases are considered less specific than the type names, and type names take precedence over aliases during template lookup. For example, if the Dynamic Data project contains templates called Int32.ascx and Integer.ascx, only the one called Int32.ascx will be used for an integer column.

Type Fallback

If there is no matching field template for a particular data type, Dynamic Data uses fallback logic to find a template for a more generic type that could be used instead. Consider the UnitsInStock column of the Product entity, which is of type Int16. When looking for a field template for this column, Dynamic Data first checks to see if a template called Int16.ascx exists. Because there is no template with this name, it uses the fallback rules shown in Table 3.2 to determine the fallback type, Int32, and tries to find a matching template for that type.

Table 3.2. Type Fallback Rules

Image

Both type names and aliases are used during template lookup for the fallback type, just as they were used for the original type. For the UnitsInStock column, this means that Dynamic Data will then try System.Int32.ascx, Int32.ascx, and Integer.ascx. Because none of these field templates exist in the default Dynamic Data project, it falls back to the next type—String and tries System.String.ascx, String.ascx, and finally choosing Text.ascx.

Control Mode

Control mode defines the context where the field template will be used. It can be one of the members of the ASP.NET DataBoundControlMode enumeration:

ReadOnly templates are used by the Details.aspx page template or custom pages to display field values in Read-only mode.

Edit templates are used by the Edit.aspx page template or custom pages to change field values of an existing row.

Insert are used by the Insert.aspx page template or custom pages to collect field values for a new row.

When looking for a ReadOnly field template for the ShippedDate column of the Order table, which has DateTime data type and no additional metadata attributes in the sample data model, Dynamic Data finds the DateTime.ascx template. Edit mode is considered more specific because it requires the field template to not only display the current field value, but also allow changing it. Therefore, when looking for an Edit field template for the ShippedDate column, Dynamic Data chooses the template called DateTime_Edit.ascx if it exists. Note that Dynamic Data uses the "_Edit" suffix for Edit templates and no suffix for the ReadOnly templates. The Insert mode is even more specific because it might require special logic to deal with rows that have not been submitted to the database, and Dynamic Data chooses the template called DateTime_Insert.ascx if it exists.

Mode Fallback

If there is no matching field template for a particular control mode, Dynamic Data uses fallback logic to find another template for a more generic mode. In this ongoing example, when looking for an Insert template for the ShippedDate column, Dynamic Data will first try to find the template called DateTime_Insert.ascx. Because there is no field template with this name, it falls back from the Insert to the Edit mode and ends up using the template called DateTime_Edit.ascx, assuming it can handle both Edit and Insert modes. Similarly, if an Edit mode template cannot be found, Dynamic Data falls back to Read-only mode.

However, before Dynamic Data falls back to the next mode, it performs the type fallback. Consider UnitsInStock, an Int16 column from the Products table. When looking for an Edit template for this field, it tries using System.Int16_Edit.ascx and Int16_Edit.ascx templates first, but because they do not exist, it falls back to type Int32 and checks for System.Int32_Edit.ascx and Int32_Edit.ascx and eventually finds Integer_Edit.ascx. If Dynamic Data performed the mode fallback first, it would skip this template and try to look for a ReadOnly template called System.Int16.ascx instead.

Navigation Columns

So far, our discussion has been about the lookup rules Dynamic Data uses for columns of primitive types that can be stored using built-in system types like Int32 and String. The Dynamic Data metadata API represents them using the MetaColumn class.

Navigation columns, on the other hand, are columns that provide access to one or more entities that are defined as custom classes in the data model itself. There are three types of navigation columns from the Dynamic Data prospective:

MetaForeignKeyColumn represents a navigation property that returns a single entity referenced by the underlying foreign key field. In the Northwind example, Product is a foreign key column of the Order_Detail entity that represents the Product entity referenced by the ProductID foreign key field.

MetaChildrenColumn is an opposite of a foreign key. In the Northwind example, Order_Details column of the Product entity returns all Order_Detail items that reference a particular product instance.

• Many-to-Many column is a special case of a MetaChildrenColumn where the IsManyToMany property is set to true. In the Northwind example, the Territories column of the Employees entity returns all territories assigned to a particular employee. Likewise, the Employees column of the Territory entity returns all employees assigned to work in a particular Territory. Dynamic Data considers both of these columns as Many-to-Many.

Navigation columns get special treatment during field template lookup. Unless the developer already placed a UIHintAttribute on a navigation property, Dynamic Data uses the rules shown in Table 3.3 to come up with a default UI Hint.

Table 3.3. Navigation Column Rules

Image

In this example, it means that for the Product column of the Order_Details table, Dynamic Data uses a template called ForeignKey.ascx; for the Order_Details column of the Product table, it uses a template called Children.ascx; and for both Employee.Territories and Territory.Employees columns, it uses the template called ManyToMany.ascx.

Effectively, there is no type fallback during template lookup for navigation columns. However, Dynamic Data does perform mode fallback, so if your page needs a foreign key template in Insert mode, it first tries ForeignKey_Insert.ascx, then ForeignKey_Edit.ascx, and then ForeignKey.ascx if necessary. The default Dynamic Data project template actually takes advantage of this to disable user interface for the children columns in Insert mode. If you open the Children_Insert.ascx field template, you see that it is empty. If this empty field template did not exist, Children.ascx would be used in its place, causing runtime errors because this template is not prepared to handle the scenario when the parent row does not exist.

Field Template Lookup Algorithm

Although the lookup rules for field templates might seem complex at a first, they are based on common-sense logic, and when you understand the idea behind them, the results will feel intuitive. Just remember that Dynamic Data tries to choose the most specific field template based on the column definition and control mode, and if such a field template does not exist, it gradually relaxes the matching rules until it finds a match or reports an error. The resulting behavior allows you to easily add new field templates where unique behavior is required to support a particular column type while allowing you to reuse existing templates with common behavior such as displaying read-only field values. Figure 3.4 shows the actual algorithm used by Dynamic Data. FieldTemplateFactory, a special class defined in the System.Web.DynamicData namespace, performs this task.

Image

Figure 3.4. Field template lookup algorithm.

As an example, consider Table 3.4, which shows the sequence of template file names Dynamic Data will try when looking for a matching field template for the HomePhone property of the Employee entity.

Table 3.4. Example of Field Template Lookup for String Column

Image

Because the HomePhone property has no UIHintAttribute and UIHint property is not specified for DynamicControl or DynamicField in page markup, the search sequence does not include the file names based on the UIHint. However, the HomePhone property does have the DataType specified in the data model using the [DataType(DataType.PhoneNumber)] attribute.

In Insert mode, the FieldTemplateFactory checks to see if PhoneNumber_Insert.ascx, System.String_Insert.ascx, String_Insert.ascx, and Text_Insert.ascx field templates exist before finding the PhoneNumber_Edit.ascx template created earlier in this chapter. If this template didn’t exist, the FieldTemplateFactory would continue checking for System.String_Edit.ascx, String_Edit.ascx, and eventually find the Text_Edit.ascx field template provided by Dynamic Data projects out of the box.

In Edit mode, the FieldTemplateFactory starts with PhoneNumber_Edit.ascx and because it exists, uses it immediately. Likewise, had this field template not been defined, it would continue the search and eventually find the Text_Edit.ascx template provided by Dynamic Data.

In ReadOnly mode, the FieldTemplateFactory starts with PhoneNumber.ascx. Because the read-only version of the phone number field template does not exist, it continues by trying System.String.ascx and String.ascx and finally finds the Text.ascx field template provided by Dynamic Data out of the box.

Table 3.5 shows another example of field template lookup sequence, this time for the UnitsInStock property of the Product entity. This column is of type Int32 and, unlike the HomePhone in the previous example, doesn’t have a DataTypeAttribute applied to it. Instead, this field template takes advantage of the fallback logic Dynamic Data uses for types and modes.

Table 3.5. Example of Field Template Lookup for Integer Column

Image

In Insert mode, the FieldTemplateFactory starts with the most specific template name (System.Int32) and mode (Insert). It tries System.Int32_Insert, Int32_Insert, and Integer_Insert before falling back to the next type—String. It continues trying System.String_Insert, String_Insert, and Text_Insert before falling back to the next mode, Edit, and repeating the steps starting with the most specific template name, System.Int32. Eventually, it finds Integer_Edit.ascx, the built-in field template provided by Dynamic Data for integer columns.


Note

For the UnitsInStock column, Dynamic Data uses both type aliases during the lookup sequence—Integer, which represents Int32, and Text, which represents String.


The Edit mode lookup sequence for the UnitsInStock column is very similar to that of Insert mode’s. It starts with System.Int32_Edit and finds the built-in Integer_Edit template. The Read-only mode is different, however. Because Dynamic Data doesn’t provide a built-in read-only template for integer columns, the FieldTemplateFactory falls back from Integer to String data type and eventually finds Text.ascx, a read-only template that can display field values of all types.


Note

Although the field template lookup algorithm might seem complex and require numerous file existence checks, in reality, Dynamic Data performs it only when a field template is needed for a particular column the first time. The results are stored in a hash table, and all subsequent lookups for this column are memory-based and very fast.


Built-in Field Templates

Dynamic Data web project templates in Visual Studio 2010 include a large number of ready-to-use field templates.

Boolean

Image

The Boolean.ascx field template is used for Boolean columns in Read-only mode. It contains a disabled CheckBox control, checked when the field value is true.

Boolean_Edit

Image

The Boolean_Edit.ascx field template is used for Boolean columns in Edit and Insert modes. It contains a CheckBox control users can use to set field value to true or false. This field template does not support null values and, unlike other well-behaved field templates, does not perform validation.

Children

Image

The Children.ascx field template is used in Read-only and Edit modes for navigation properties that represent the many side of one-to-many relationships between entities. For example, the Customer entity in the Northwind sample data model has a children navigation property called Orders, which returns a collection of all orders placed by a given customer. In Read-only and Edit modes, the Children.ascx entity template displays a hyperlink to the dynamic List.aspx page that displays all child rows of the parent entity.

Children_Insert

The Children_Insert.ascx field template is empty. Because the dynamic List.aspx page cannot display child rows of a parent entity that has not been submitted to the database, this template prevents the Children.ascx field template from being used in Insert mode.

DateTime

Image

The DateTime.ascx field template is used in Read-only mode to display DateTime field values. This field template contains a Literal control that injects the field value directly into the web page without any adorning HTML elements. This template is nearly identical to the Text.ascx template described in the following sections and could be removed, making Text.ascx responsible for displaying DateTime field values in Read-only mode as well.

DateTime_Edit

Image

The DateTime_Edit.ascx field template is used for DateTime columns in Edit and Insert mode. It contains a TextBox control, accompanied by a CustomValidator, used to make sure that the value entered in the TextBox is a valid DateTime. It also contains a RequiredFieldValidator, used to enforce values for columns marked with the RequiredAttribute, a RegularExpressionValidator, used to enforce regular expression patterns for columns marked with the RegularExpressionAttribute and a DynamicValidator, used to enforce all other validation attributes applied to this column.

Decimal_Edit

Image

The Decimal_Edit.ascx field template is used for Decimal, Float, and Double columns in Edit and Insert mode. It contains a TextBox control, accompanied by a CompareValidator, used to ensure that values entered in the TextBox are valid numbers. It also contains a RequiredFieldValidator, used to enforce values for columns marked with the RequiredAttribute; a RangeValidator, used to enforce range of values for columns marked with the RangeAttribute; a RegularExpressionValidator, used to enforce regular expression patterns for columns marked with the RegularExpressionAttribute; and a DynamicValidator, used to enforce all other validation attributes applied to this column.

EmailAddress

Image

The EmailAddress.ascx field template is a read-only template used for String columns marked with the DataType(DataType.EmailAddress) attribute. It includes a HyperLink control that displays the field value as a link with the URL scheme "mailto:". When the user clicks this link, most web browsers launch the default e-mail client installed on the computer and create a new message with the field value automatically added in the “To” list.

Enumeration

Image

The Enumeration.ascx field template is used for enumeration columns in Read-only mode. It contains a Literal control that displays the underlying integral field value converted to its equivalent enumerated value and then converted to a String.


Note

Enumeration columns represent properties with an actual enumerated .NET data type (supported only by LINQ to SQL today) or integer properties that have been marked with the EnumDataTypeAttribute (supported by both LINQ to SQL and Entity Framework). As an example, consider the following enumerated type that could be used to track status of Orders in the Northwind database:

public enum OrderStatus: byte
{
  Draft = 0,
  Submitted = 1,
  PaymentProcessed = 2,
  Fulfilled = 3
}

In the sample data model, it could be expressed as an integer property called OrderStatus in the Order entity:

[EnumDataType(typeof(OrderStatus))]
public byte OrderStatus { get; set; }

By marking the OrderStatus property with the EnumDataTypeAttribute, you can make Dynamic Data treat it as enumeration instead of an integer and use the Enumeration.ascx field template, which displays OrderStatus field values as “Draft” and “Submitted,” instead of “1” and “2.”


Enumeration Edit

Image

The Enumeration_Edit.ascx field template is used for enumeration columns in Edit and Insert modes. It contains a DropDownList control, populated with enumerated items converted to string, plus “[Not Set]” if the column allows null values. This field template also includes a RequiredFieldValidator to enforce values for columns marked with the RequiredAttribute and a DynamicValidator to enforce all other validation attributes applied to this column.


Note

When converting enumeration values to string, the Enumeration field templates do not automatically separate words concatenated to form a valid programmatic identifier. For example, an enumerated value ReadOnly would be normally displayed as “read-only” in a hand-coded web page. To make display names of the enumeration values more user-friendly, you can modify the Enumeration field templates to implement appropriate logic based either on the naming convention used to define the enumerated values, commonly PascalCase in .NET programs. Alternatively, you can use metadata attributes, such as DisplayAttribute, that can be applied to the enumerated values to specify the exact display string. Chapter 11, “Building Dynamic Forms,” shows how to implement this.


ForeignKey

Image

The ForeignKey.ascx is used for foreign key columns in Read-only mode. It contains a HyperLink control that displays the field value of the “display” column of the parent table. You can specify the display column explicitly by applying the DisplayColumnAttribute to the parent entity class, or it can be selected automatically based on the Dynamic Data heuristics. Users can click the link generated by the control to navigate to the List.aspx page of the parent table.

ForeignKey_Edit

Image

The ForeignKey_Edit.ascx field template is used for foreign key columns in Edit and Insert modes. It contains a DropDownList control that displays all rows from the parent table. The display column of the parent table determines the Text of each ListItem, and its primary key columns determine its Value.

Integer_Edit

Image

The Integer_Edit.ascx field template is used for Byte, Int16, Int32, and Int64 columns in Edit and Insert modes. It contains a TextBox control, accompanied by a CompareValidator, which is used to ensure that values entered in the TextBox are valid numbers. It also contains a RequiredFieldValidator, used to enforce values for columns marked with the RequiredAttribute; a RangeValidator, used to enforce range of values for columns marked with the RangeAttribute; a RegularExpressionValidator, used to enforce regular expression patterns for columns marked with the RegularExpressionAttribute; and a DynamicValidator, used to enforce all other validation attributes applied to the column.

ManyToMany

Image

The ManyToMany.ascx field template is used for children columns in a many-to-many relationship, such as the Employees column of the Territory entity in the Northwind sample database. This template contains a Repeater control that generates a DynamicHyperLink for every child entity. On the actual page, this looks like a list of hyperlinks that the user can click to navigate to the Details.aspx page of a particular child entity.


Note

Many-to-many relationships are natively supported in Entity Framework but not in LINQ to SQL. Therefore, only the Entity Framework flavors of the Dynamic Data project templates in Visual Studio include the ManyToMany field template. Unlike other field templates, which work equally well with both data access frameworks, the ManyToMany field template uses Entity Framework APIs directly.

LINQ to SQL natively supports only one-to-many relationships and requires you to have an explicit many-to-many entity in the model. However, it is possible to mimic many-to-many relationships by implementing a simple coding pattern as Eric Smith and Shannon Davidson describe in the article published on the Code Project, which can be found at the following location online:

http://www.codeproject.com/KB/linq/linq-to-sql-many-to-many.aspx

It is possible to create Dynamic Data many-to-many field templates for LINQ to SQL based on this approach. However, this exercise is outside the scope of this chapter.


ManyToMany_Edit

Image

The ManyToMany_Edit.ascx field template is used for many-to-many children columns in Edit and Insert modes. This template contains a CheckBoxList control that generates a check box for every entity the user can check to add it to the list of children.

MultilineText_Edit

Image

The MultilineText_Edit.ascx field template is used for long string columns in Edit and Insert modes. It contains a TextBox control with TextMode property set to MultiLine. It also contains a RequiredFieldValidator, used to enforce values for columns marked with the RequiredAttribute, a RegularExpressionValidator, used to enforce regular expression patterns for columns marked with the RegularExpressionAttribute and a DynamicValidator, used to enforce all other validation attributes applied to the column.

String columns are considered long when they do not have maximum length specified in the data model, such as the Notes column of the Employee entity in the Northwind sample, which has type NTEXT. You can also force Dynamic Data to use the MultilineText_Edit field template for columns that do have maximum length by applying the DataType(DataType.MultilineText) attribute to their properties in the data model.

Text

Image

Due to the data type fallback used during template lookup, the Text.ascx field template can be used in Read-only mode for columns of all primitive types with the exception of Boolean and DateTime columns, for which Dynamic Data provides specific templates. This field template includes a Literal control that displays the field value converted to a string.

Text_Edit

Image

The Text_Edit.ascx field template is used for string columns in Edit and Insert modes. It includes a TextBox control, accompanied by a RequiredFieldValidator, used to enforce values for columns marked with the RequiredAttribute; a RegularExpressionValidator, used to enforce regular expression patterns for columns marked with the RegularExpressionAttribute; and a DynamicValidator, used to enforce all other validation attributes applied to the column.

Url

Image

The Url.ascx field template is used for columns marked with the DataType(DataType.Url) attribute. It contains a HyperLink control that displays the field value as a link in the generated HTML. The "http://" scheme is automatically added to the URL unless the field value already contains it. Only HTTP and HTTPS schemes are recognized automatically. Although this field template does not require the column type to be only String, the field value converted to string must be a valid URL for the generated hyperlink to work correctly.

Summary

A field template is a special type of ASP.NET user control that inherits from the FieldTemplateUserControl base class provided by Dynamic Data. Multiple columns can reuse the same field template based on its compatibility with the column type and control mode. Changing a single field template automatically affects the user interface generated for all matching columns in the data model. Dynamic Data project template comes with a reasonable number of field templates that allow developers to create working web applications for many data types out of the box. Developers can easily modify the default field templates as well as add new ones to meet specific requirements of their projects.

Dynamic Data supports separate templates for Read-only, Edit, and Insert modes. Although a single template can support all three modes and programmatically display different versions of child controls, separating this logic into different templates helps to keep them simple and lightweight. Dynamic Data uses common-sense logic to find the best matching field template based on the column type and required control mode. If the most specific template does not exist, Dynamic Data gradually relaxes the matching rules and tries to find templates for a more generic column type and control mode.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.37.196