Introduction
The GridView and DetailsView controls offer built-in editing functionality that can be turned on with the tick of a checkbox. Without writing a line of declarative markup
or server-side source code, the page developer gets a decent out of the box editing interface. Namely, each field in the GridView or DetailsView is rendered in its editing
interface; BoundFields display a TextBox control while CheckBoxFields display an enabled checkbox. Moreover, a CommandField is added, which displays the Edit, Update, and
Cancel buttons, as needed.
While the ListView control provides editing support, it requires a bit more work from the page developer to get it going. The reason is because the ListView is defined by
templates whereas the GridView and DetailsView are defined by fields. Many fields types, such as the BoundField, can generate their own editing interface, but with templates
the page developer is on the hook for specifying the editing interface. Creating an editable ListView control entails defining the editing interface via the
EditItemTemplate and adding the Edit, Update, and Cancel buttons in the appropriate spots.
This article walks through creating an editable ListView control, with the finished results available for download at the end of the article. Read on to learn more!
An Overview of the ListView's Editing Workflow
A ListView control that supports editing typically includes an Edit button with each item that, when clicked, displays that item's editing interface. The editing interface
includes Web controls for editing the item's data - TextBoxes, DropDownLists, CheckBoxes, and so on - along with Update and Cancel buttons. Clicking the Cancel button returns
the item to its pre-editing, read-only state whereas clicking the Update button saves the user's modifications in the database (or wherever) and then returns the item
to its read-only state, showing its newly updated values. The screen shot below shows a ListView control that lists the products from the Northwind database table. Note
that all of the read-only items have an Edit button. However, the product Aniseed Syrup has had its Edit button clicked and is rendered in its edit mode. The editing
interface displays TextBoxes and DropDownList controls for the various fields and has Update and Cancel buttons instead of the Edit button.
Whenever one of the Edit buttons is clicked a postback ensues and the ListView begins its editing workflow. (In the screen shot above the "Edit button" is the pencil icon
and is implemented as an ImageButton.) This workflow proceeds as follows:
The ListView raises its ItemEditing event.
The ListView sets its EditIndex property to the index of the row whose Edit button was clicked.
The ListView rebinds to its data source.
The row whose index corresponds to the EditIndex value has its EditItemTemplate rendered (instead of its ItemTemplate)
The net effect of the above workflow is that clicking an item's Edit button causes that item's editing interface to be displayed. You, the page developer, are responsible for
defining this editing interface. We'll create the editing interface you see above later on in this article, but for now understand that in addition to the data entry controls
the editing interface needs to also include Update and Cancel buttons. The Cancel button, if clicked, causes a postback and kicks off the canceling workflow:
The ListView raises its ItemCanceling event.
The ListView sets its EditIndex property to -1.
The ListView rebinds to its data source.
All rows are displayed in their read-only mode (because no row has an index of -1).
If the Update button is clicked a postback ensues and the updating workflow unfolds:
The ListView raises its ItemUpdating event.
The ListView assigns the values supplied in the editing interface to the update parameters for its associated data source control.
The ListView assigns the key values for the row being updated to the update parameters for its associated data source control.
The ListView calls its associated data source control's Update method, which actually performs the update.
The ListView raises its ItemUpdated event handler.
The ListView sets its EditIndex property to -1.
The ListView rebinds to its data source.
After the updating workflow completes, the ListView displays all of the data in read-only mode because the EditIndex has been set to -1. Furthermore, the
just-updated record's new values are displayed in the read-only interface because the data is rebound to the ListView (step 7) after the update is issued (step 4).
From the end user's perspective, the end-to-end data modification workflow unfolds like this: the user clicks the Edit button; there's a short pause before that
item's editing interface is displayed. The user modifies the data as needed and clicks the Update button, which saves the data and returns the screen to its pre-editing
view.
Implementing the Read-Only Interface (ItemTemplate)
Adding updating support to the ListView requires that the ListView's underlying data source control support updating. That means that if you are using a SqlDataSource
or AccessDataSource control as the ListView's data source that the SqlDataSource (or AccessDataSource) must have an UpdateCommand specified. If you are using an
ObjectDataSource then you will need to have specified what object method to invoke to perform the update. For more background on configuring the data source controls to support
updating, refer to Accessing and Updating Data in ASP.NET: Updating Basics.
Recall that in order to display the editing interface there needs to be some Button control in the ItemTemplate that serves as the Edit button. This button can
be any type of Button control (a regular Button, a LinkButton, or an ImageButton), but it must have its CommandName property set to "Edit". The demo available
for download at the end of this article includes a ListView that displays records from the Northwind database's Products table. The markup for the ItemTemplate
displays each product's ProductName field in an <h3> element as well as the product's supplier, category, and unit price. There's
also an ImageButton control (the pencil icon) that serves as the Edit Button. Note that its CommandName property is set to "Edit".
Along with adding an Edit button, it's also equally important that the ListView's DataKeyNames property be set to the column(s) that comprise the primary key.
The Products table's primary key is ProductID. Therefore, in order for this ListView to correctly implement deleting it is imperative that its
DataKeyNames property be set to ProductID, as it is in the markup above. If this property is not set then the updating workflow will not work.
Any changes made to the editing interface will not be saved back to the database.
Implementing the Editing Interface (EditItemTemplate)
The editing interface is defined via the ListView control's EditItemTemplate. This template must contain the data entry Web controls to collect the necessary
inputs, along with Edit and Cancel buttons. What input needs to be collected depends on the data source control's update logic. For example, if you are using a SqlDataSource
control that has an UpdateCommand statement like:
UPDATE Products SET
ProductName=@ProductName,
UnitPrice=@UnitPrice
WHERE ProductID = @ProductID
Then you would need two input controls in the EditItemTemplate: one for ProductName and one for UnitPrice. (The value for the
primary key field ProductID is retrieved via the ListView's DataKeys collection, which is why it is essential that you set the ListView's
DataKeyNames property to the primary key column.)
When the EditItemTemplate is first rendered the input Web controls need to show the current values of the item being edited. Then, when the user clicks the
Update button, the user's inputs need to be sent off to the data source control. This can be accomplished without writing any code by using two-way data binding. Two-way
data binding is implemented by using the syntax <%# Bind("columnName") %> on the input Web control's appropriate property. For TextBox controls you'd
use the Bind syntax on the Text property; for DropDownLists you'd use it on the SelectedValue property. The following markup,
from the ListView's EditItemTemplate, shows this two-way databinding syntax in action with two TextBoxes for the ProductName and UnitPrice fields
and two DropDownLists for the CategoryID and SupplierID fields:
In addition to the TextBox and DropDownList controls, the EditItemTemplate also contains the Update and Cancel buttons. As with the Edit button, these can be implemented as
Button, LinkButton, or ImageButton controls. What is key is that their CommandName properties be set to "Update" and "Cancel".
Also note that you can add validation controls to the EditItemTemplate to ensure that the user's inputs are valid. In the example above I added a RequiredFieldValidator
for the txtProductName TextBox because ProductName is a required field in the database. I also added a CompareValidator for the txtUnitPrice
TextBox to ensure that the user enters a valid currency value greater than or equal to zero.
Finally, examine the DropDownLists. Note that I've set the AppendDataBoundItems to True and added a static ListItem with an empty string as the
Value and the Text "None / Unknown". This handles the NULL case. The Products table allows for NULL values for
its CategoryID and SupplierID columns. To correctly display the editing interface for a product that has a NULL value for one of these columns and
to allow the user to set a product's CategoryID or SupplierID value to NULL we need to use the above approach. See
Accessing and Updating Data in ASP.NET 2.0: Handling Database NULL Values for more information on this
topic.
What If I'm Not Using a Data Source Control?
The ListView control can be bound to data via a data source control or by programmatically settings its DataSource property and calling its DataBind
method. If you use this latter approach then you cannot take advantage of the automatic updating capabilities of the data source control. Instead, you will need to create
an event handler for the ListView's ItemUpdating event and implement your own updating logic there.
Short-Circuiting the Updating Workflow
In some scenarios you may want to cancel the updating workflow based on the user's input or some other type of programmatic logic. Perhaps any user can increase the price of
a product but only certain users can decrease the price. Or maybe you want to parse the user's input for the ProductName field and prohibit the update if there
are any curse words in the product name.
Whatever the rationale may be, you have an opportunity to examine both the original values and the user's edits before the update is committed via the ItemUpdating event
handler. The demo available at the end of this article includes such an event handler that checks to see if the ProductName value entered by the user contains
more than three words. If such a lengthy product name is found then the update is canceled and the user is shown a message explaining the issue.
The code for the ItemUpdating event handler is straightforward. It pulls the value entered into the ProductName field via the e.NewValues collection.
It then splits on spaces (" "). If there are more than two spaces in the product name then, presumably, there are more than three words, so the update is canceled by setting
e.Cancel to True and a message is displayed via the DisplayAlert method, which is defined in a custom base Page class.
Protected Sub lvProducts_ItemUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewUpdateEventArgs) Handles lvProducts.ItemUpdating
'Make sure product name does not contain more than three words
'Split on " "
Dim words() As String = e.NewValues("ProductName").ToString().Trim().Split(New Char() {" "})
If words.Length > 2 Then
'Invalid product name!
e.Cancel = True
MyBase.DisplayAlert("You cannot have more than three words in the product name. Please shorten your product name and try again.")
End If
End Sub
The following screen shot shows the client-side messagebox that is displayed when the user attempts to enter a product name that's more than three words (such as "Aniseed
Syrup Is Good!")
Conclusion
The ListView control provides inserting, updating, and deleting functionality. As we saw in this installment, adding editing capabilities to the ListView is relatively straightforward:
add an Edit button to the ItemTemplate, define the editing interface via the EditItemTemplate, and add Update and Cancel buttons to the
EditItemTemplate. That's it! The data source control handles the actual updating of data.
The next installment shows how to insert data through the ListView control.