To read the article online, visit http://www.4GuysFromRolla.com/articles/080807-1.aspx

Accessing and Updating Data in ASP.NET: Customizing the Editing Interface

By Scott Mitchell


Introduction


In the last installment of this article series, Updating Basics, we looked at how to configure the SqlDataSource control to issue UPDATE statements to a database. We then saw how the GridView control can work in tandem with the SqlDataSource control to provide a simple web-based editing interface composed of textboxes for each data field. While this simplified interface enabled developers to create an editable interface with zero code and just a few clicks of the mouse, the interface is so simple that it is impractical for all but the most trivial scenarios. Some of these limitations were exhibited in the Updating Basics article when attempting to update a product's Category. In short, you had to modify the product's CategoryID value, meaning that to change a product's category from Beverages to Dairy you would have to change the CategoryID value from 1 to 4. Likewise, the simplified interface lacks any input validation that may be necessary when editing required fields or fields that must appear in a particular format (like dates or numbers).

Fortunately, the GridView's editing interface can be customized to include validation controls and alternative user interface elements. It requires a little more effort, but in most cases these changes can be completed entirely through the Designer or the page's declarative markup. In this installment we will extend the simplified editing interface from Updating Basics to include validation controls for the ProductName and UnitPrice fields; we will also replace the CategoryID data field's textbox with a drop-down list that enumerates the possible categories. Read on to learn more!

How the Editing Interface is Generated


As we saw in the Updating Basics article, a GridView can be made editable when it is bound to a data source control that has updating capabilities enabled. A SqlDataSource control is configured as such when it has its UpdateCommand property specified. In the case of a SqlDataSource, the UpdateCommand specifies the UPDATE statement or stored procedure that is executed when the data source control's Update method is invoked.

From the Visual Studio Designer, the GridView can be marked as editable by checking the "Enable Editing" checkbox in the GridView's smart tag or by manually adding a CommandField to the GridView whose ShowEditButton property is set to True. From the end user's perspective, this adds a column of Edit buttons to the grid. Clicking an edit button causes a postback and raises the GridView's RowEditing event. After the event is raised, the GridView re-renders itself, but with the selected row in edit mode.

The row being edited has each of its columns rendered in their edit mode. For BoundFields whose ReadOnly property is not True, a TextBox Web control is used and its Text property is assigned the value of that cell. CheckBoxFields are rendered with a clickable checkbox. Since our example in the Updating Basics article used BoundFields and a CheckBoxField, the editing interface was composed of TextBox controls and an enabled CheckBox control.

In order to customize the editing interface - either to add input validation or to use an alternative user interface control - we need to use a TemplateField in place of a BoundField. TemplateFields are composed of read-only and editing templates (among others). A template allows the page developer to specify a mix of static HTML, Web controls, and databinding syntax within the template. When displaying a row in edit mode, for any TemplateFields their EditItemTemplates are used to render the editing interface. If the TemplateField lacks an EditItemTemplate then the ItemTemplate is used instead. (For more background on GridView TemplateFields, see GridView Examples for ASP.NET 2.0: Working with TemplateFields.)

Steps for Customizing the Editing Interface


In order to customize the editing interface for a particular column in the GridView we need to use a TemplateField. This customization process involves the following steps:
  1. Add a new TemplateField to the GridView's columns for the custom editing interface. Alternatively, if you already have a BoundField you can convert the existing BoundField into a TemplateField by clicking the "Convert this field into a TemplateField" link in the Fields dialog box. To get to the Fields dialog box, click the Edit Columns link from the GridView's smart tag. Next, select the column to convert to a TemplateField and click the link.

    The Fields dialog box.

  2. Edit the EditItemTemplate. This can be done directly through the page's declarative syntax by hand-entering the HTML and Web control syntax. If you prefer the Designer, click the Edit Templates link from the GridView's smart tag. From here you can choose the template to edit and then drag and drop controls from the Toolbox into the template design-time interface.
  3. If you are creating an alternative user interface for editing, add the necessary Web controls to the EditItemTemplate.
  4. Add any validation controls and configure their properties as needed.
  5. If you are using an alternative user interface or if you are adding the TemplateField manually then you need to use two-way databinding to associate the update parameter value with the Web control property in the EditItemTemplate. This step is unnecessary if you converted an existing BoundField to a TemplateField and did not change add new Web controls for collecting user input because the conversion process automatically adds a TextBox to the EditItemTemplate and uses two-way databinding to associate the data field with the TextBox's Text property.
Two-way databinding is a specialized syntax that informs the GridView to take a particular value from the editing interface and to associate it with a particular parameter in its data source control's UpdateParameters collection. For example, in the GridView we have a data field called ProductName that displays the product's name. There's a parameter in the UpdateParameters collection named ProductName as well and this parameter is used in the data source control's UpdateCommand. If we use a TemplateField as opposed to a BoundField for the ProductName column then we would need to use two-way databinding that says to the GridView, "Hey, when the user clicks the Update button, assign the value in this TextBox's Text property to the ProductName parameter."

In addition to assigning the user-entered value into the appropriate update parameter, two-way databinding also sets the Text property of the TextBox to the value of the data field when the record's Edit button is clicked. In short, two-way databinding relieves us from having to write code in this situation. Editing with the DataGrid control in ASP.NET 1.x requires writing code to populate the editing interface with values when a row is edited as well as taking the user's updated values and saving them back to the database.

Applying Two-Way Databinding


There are two ways to specify two-way databinding: by manually entering it through the page's declarative syntax; or by using the Edit DataBindings dialog box. Let's examine both approaches. To enter it through the Designer, go to the Edit Templates interface and select the appropriate template. There should be just user input Web control from which the user's input is collected. This might be a TextBox or a DropDownList or a CheckBox. We want to use two-way databinding on this control (and not on the validation control or other controls in the template that are not the one that collects the user input). From this control's smart tag click the "Edit DataBindings" link. This will bring up a dialog box like the one seen below.

The Edit DataBindings dialog box.

The Web control's bindable properties are listed on the left. Select one and then choose a field to bind it to from the right. Alternatively, you can enter the binding express by hand in the Custom binding textbox. Use the syntax: Bind("DataField_Name").

The Edit DataBindings dialog box simply injects the appropriate two-way databinding markup into the Web control's declarative syntax. You can enter this manually, if you'd prefer, instead of using the Edit DataBindings dialog box. For example, to bind the ProductName TextBox's Text property to the ProductName data field use the following syntax in the TemplateField's EditItemTemplate:

<EditItemTemplate>
   <asp:TextBox ID="ProductName" runat="server" Text='<%# Bind("ProductName") %>'></asp:TextBox>
</EditItemTemplate>

When entering this syntax by hand it is essential that you delimit the property value with apostrophes instead of quotation marks since quotation marks are used within the Bind statement. That is, I use Text='<%# Bind("ProductName") %>' rather than Text="<%# Bind("ProductName") %>".

Adding Validation Controls to the Editing Interface


The GridView example we explored in Updating Basics included four editable columns: ProductName, UnitPrice, CategoryID, and Discontinued. The first three columns are displayed as BoundFields, which results in a TextBox for the editing interfaces. These editing interfaces lack any sort of input validation. If a user enters invalid input and attempts to update the database, an exception will be thrown. For example, ProductName does not allow NULL values, so if a user omits a value here an exception will be thrown. Similarly, UnitPrice is a money field. If a user attempts to enter an illegal value (like "Cheap!!"), the database will throw an exception because it cannot cast it to a money value.

The example available at the end of this article uses TemplateFields for the ProductName and UnitPrice columns so that validation controls can be added. A RequiredFieldValidator is added to the ProductName column while the UnitPrice column uses a CompareValidator to ensure that the value entered is a valid currency.

ASP.NET 2.0's validation controls include a ValidationGroup property that can partition validation controls on a page into independent groups. This feature is useful on pages where there are multiple places on a single page where different data can be modified. In any event, if you need to use the ValidationGroup property of the validation controls in the GridView's columns' customized editing interfaces, it is essential that you set the CommandField's ValidationGroup property to the same value.

For more background on the ValidationGroup property and new features added to ASP.NET 2.0's validation controls, see my article Dissecting the Validation Controls in ASP.NET 2.0.

Using a Drop-Down List Instead of a TextBox


For certain data fields, a TextBox does not make sense. The CategoryID data field is a prime example. In the Products database table, each product is assigned to a category via its CategoryID field. The Categories table contains a record for each existing category. When editing the data through a GridView using the default TextBox editing interface, a user must edit the category by typing in the appropriate CategoryID. Such an interface is not very user friendly, as it assumes the user knows the category ID values. Moreover, if the user enters an invalid ID (that is, an ID that does not map to a record in the Categories table) and clicks Update, an exception will be thrown by the database due to the foreign key constraint between the Products and Categories tables.

Clearly, we need a better interface. For such look-up data, a drop-down list is usually the best interface. We want our DropDownList to list all of the possible categories and to automatically select the edited product's current category selection. The user can then modify the product's category by picking a different option from the list.

To start, create a TemplateField or convert the existing CategoryID BoundField into a TemplateField. Next, edit the EditItemTemplate so that it contains just a DropDownList control. From the DropDownList control's smart tag, bind it to a new SqlDataSource control that returns the CategoryID and CategoryName columns from the Categories table, ordered by CategoryName. If you visit the page at this point and edit a row, you should see a drop-down list of all categories; however, the particular product's category won't be selected, and what's more is that when you save the product it will disappear from the grid altogether!

This behavior exists because we have yet to apply our two-way databinding to the DropDownList. Without this information the GridView does not select the appropriate item in the list when the Edit button is clicked. When the row is updated, the lack of the two-way databinding syntax results in a NULL value for the product's CategoryID. Since the SqlDataSource control's SelectCommand uses an INNER JOIN on Products and Categories, any products without a corresponding category are not returned by the query and therefore are not displayed in the grid.

To remedy this, use two-way databinding to bind CategoryID to the SelectedValue property of the DropDownList. The following declarative syntax shows the EditItemTemplate for the CategoryID column. Note that there is a DropDownList present and a SqlDataSource control that returns the set of categories. Also inspect the two-way databinding used in the DropDownList's markup.

<EditItemTemplate>
   <asp:DropDownList ID="CategoriesDDL" runat="server" DataSourceID="CategoriesDataSource"
      DataTextField="CategoryName" DataValueField="CategoryID" SelectedValue='<%# Bind("CategoryID") %>'>
   </asp:DropDownList>

   <asp:SqlDataSource ID="CategoriesDataSource" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
      SelectCommand="SELECT [CategoryID], [CategoryName] FROM [Categories] ORDER BY [CategoryName]">
   </asp:SqlDataSource>
</EditItemTemplate>

Conclusion


The GridView control makes it easy to edit data. As we saw in this article, with a little bit of effort it's possible to customize the editing interface to include input validation and alternative user interface elements. And all of this is possible without writing a lick of code.

One subtlety we did overlook in this article is dealing with database fields that allow NULL values. The CategoryID value does allow NULLs, but our query only returns products with categories. This actually simplifies the editing interface, but in a real-world application we might want to show those products that have a NULL value for their CategoryID. Furthermore, we would want to be able to edit those products and assign them a category. Likewise, we would want to be able to take a product with a category and change that category to a NULL value. We'll explore these topics in a future installment.

Until then... Happy Programming!

  • By Scott Mitchell


    Attachments:


  • Download the code used in this article

    Further Readings:


  • Tutorials on Editing, Inserting, and Deleting Data (using the ObjectDataSource)
  • Inserting, Updating, and Deleteing Data with the SqlDataSource (VB Version) (C# version)
  • Adding Validation Controls to the Editing and Inserting Interfaces (VB Version) (C# version)
  • Customizing the Data Modification Interface (VB Version) (C# version)
  • Article Information
    Article Title: ASP.NET.Accessing and Updating Data in ASP.NET: Customizing the Editing Interface
    Article Author: Scott Mitchell
    Published Date: August 8, 2007
    Article URL: http://www.4GuysFromRolla.com/articles/080807-1.aspx


    Copyright 2017 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers