Accessing and Updating Data in ASP.NET: Customizing the Editing InterfaceBy Scott Mitchell
In the last installment of this article series, Updating Basics, we looked at how to configure the SqlDataSource control to issue
UPDATEstatements 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
CategoryIDvalue, meaning that to change a product's category from Beverages to Dairy you would have to change the
CategoryIDvalue 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
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
UpdateCommandproperty specified. In the case of a SqlDataSource, the
UPDATEstatement or stored procedure that is executed when the data source control's
Updatemethod 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
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
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
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:
- 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.
- 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.
- If you are creating an alternative user interface for editing, add the necessary Web controls to the
- Add any validation controls and configure their properties as needed.
- 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
EditItemTemplateand uses two-way databinding to associate the data field with the TextBox's
ProductNamethat displays the product's name. There's a parameter in the UpdateParameters collection named
ProductNameas 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
ProductNamecolumn 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
Textproperty to the
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 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:
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
Text property to the
ProductName data field use the
following syntax in the TemplateField's
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") %>'
Text="<%# Bind("ProductName") %>".
Adding Validation Controls to the Editing Interface
The GridView example we explored in Updating Basics included four editable columns:
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,
ProductNamedoes not allow
NULLvalues, so if a user omits a value here an exception will be thrown. Similarly,
moneyfield. 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
columns so that validation controls can be added. A RequiredFieldValidator is added to the
ProductName column while
UnitPrice column uses a CompareValidator to ensure that the value entered is a valid currency.
ASP.NET 2.0's validation controls include a
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
CategoryIDdata field is a prime example. In the
Productsdatabase table, each product is assigned to a category via its
Categoriestable 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
Categoriestable) and clicks Update, an exception will be thrown by the database due to the foreign key constraint between the
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
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
Since the SqlDataSource control's
SelectCommand uses an
INNER JOIN on
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.
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
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
NULL value. We'll explore these topics in a future installment.
Until then... Happy Programming!