Accessing and Updating Data in ASP.NET 2.0: Customizing the Editing Interface
By Scott Mitchell
A Multipart Series on ASP.NET 2.0's Data Source Controls
ASP.NET 2.0 introduced a number of new Web controls designed for accessing and modifying data.
These controls allow page developers to declaratively access and modify data without writing any
code to perform the data access. This article is one in a series of articles on ASP.NET 2.0's new data
source controls.
Data Source Control Basics - explores the concepts
and advantages of data source controls, and compares their usage in ASP.NET 2.0 to data access techniques in ASP.NET 1.x.
Accessing Database Data - shows how to use the
SqlDataSource and AccessDataSource controls to query data from a relational database.
Filtering Database Data with Parameters - learn how to
retrieve just a subset of database data based on hard-coded values and values from the querystring, other Web controls on the page,
session variables, and so on.
Creating Custom Parameter Controls - learn how
to create your own custom, declarative Parameter controls for use in the data source controls' parameters collections.
Inserting Data - learn how to insert data using
a SqlDataSource control. Also examines how to retrieve the IDENTITY column value for the just-inserted record.
Deleting Data - see how to delete data using
a SqlDataSource control. Also looks at how to programmatically cancel a delete.
Updating Basics - learn the basics of updating database data using a
SqlDataSource control. Also examines using the GridView to provide a web-based editing interface.
Customizing the Editing Interface - see how to
customize the GridView's columns to provide a customized editing interface that includes input validation and alternative
user interface elements.
Handling Database NULL Valuese - explore how to
extend the GridView's customized editing interface to handle database NULL values.
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:
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 EditItemTemplate.
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 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 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:
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.
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.
<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.
A Multipart Series on ASP.NET 2.0's Data Source Controls
ASP.NET 2.0 introduced a number of new Web controls designed for accessing and modifying data.
These controls allow page developers to declaratively access and modify data without writing any
code to perform the data access. This article is one in a series of articles on ASP.NET 2.0's new data
source controls.
Data Source Control Basics - explores the concepts
and advantages of data source controls, and compares their usage in ASP.NET 2.0 to data access techniques in ASP.NET 1.x.
Accessing Database Data - shows how to use the
SqlDataSource and AccessDataSource controls to query data from a relational database.
Filtering Database Data with Parameters - learn how to
retrieve just a subset of database data based on hard-coded values and values from the querystring, other Web controls on the page,
session variables, and so on.
Creating Custom Parameter Controls - learn how
to create your own custom, declarative Parameter controls for use in the data source controls' parameters collections.
Inserting Data - learn how to insert data using
a SqlDataSource control. Also examines how to retrieve the IDENTITY column value for the just-inserted record.
Deleting Data - see how to delete data using
a SqlDataSource control. Also looks at how to programmatically cancel a delete.
Updating Basics - learn the basics of updating database data using a
SqlDataSource control. Also examines using the GridView to provide a web-based editing interface.
Customizing the Editing Interface - see how to
customize the GridView's columns to provide a customized editing interface that includes input validation and alternative
user interface elements.
Handling Database NULL Valuese - explore how to
extend the GridView's customized editing interface to handle database NULL values.