Sunday, October 23, 2011
ListView and DataPager Controls: Inserting Data with DropDownlist
Introduction
The ListView control is similar to the GridView control in many ways: both display a set of records, both support built-in sorting, paging, editing, and deleting functionality with minimal effort. The ListView differs from the GridView in two key ways:
- Rather than using fields, the ListView is rendered via templates, which offers the page developer much finer control over the emitted markup, and
- The ListView supports built-in inserting support
InsertItemTemplate
and specifying where the inserting interface should go via the InsertItemPosition
property. Much like with editing data from within the ListView, the InsertItemTemplate
can contain two-way databinding statements when using a data source control to get the inputs entered by the user from the ListView's inserting interface into the parameters of the data source control. And like with the editing and deleting workflows, you can programmatically examine and modify the user's submitted data before inserting the data, cancelling the operation altogether if needed.This article walks through the steps for creating a ListView that allows users to insert records. It also shows how to optionally cancel the inserting workflow based on programmatic logic. Read on to learn more!
An Overview of the ListView's Inserting Workflow
A ListView control that supports inserting includes some sort of inserting interface. This interface includes input Web controls to collect the data to add a new record - TextBoxes, CheckBoxes, DropDownLists, and so forth - along with Insert and Cancel buttons. Clicking the Insert button adds a new record using the user-supplied values; the Cancel button, when clicked, resets the inserting interface to its initial state by clearing out the TextBoxes, returning the DropDownLists to the first item, and so on.The screen shot below shows a ListView control that has an inserting interface defined and has it displayed as the first item. In other words, it appears before any other content defined in the
ItemTemplate
. The inserting interface may be displayed as the first or last item; it's location is configured via the InsertItemPosition
property. The Insert button in the screen shot below is implemented as an ImageButton and displays a green plus icon.- The ListView raises its
ItemInserting
event. - The ListView assigns the values supplied in the inserting interface to the insert parameters for its associated data source control.
- The ListView calls its associated data source control's
Insert
method, which actually performs the insert. - The ListView raises its
ItemInserted
event handler. - The ListView rebinds to its data source.
Implementing the Inserting Interface (InsertItemTemplate
) and Setting the
Adding inserting support to the ListView requires that the ListView's underlying data source control support inserting. 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
InsertCommand
specified. If you are using an ObjectDataSource then you will need to have specified what object method to invoke to perform the insert. For more background on configuring the data source controls to support inserting, refer to Accessing and Updating Data in ASP.NET: Inserting Data.Recall that implementing inserting involves two key steps: defining the inserting interface via the InsertItemTemplate
and specifying where the inserting interface should be placed via the InsertItemPosition
property. The InsertItemTemplate
must contain the input Web controls to collect the user's input. The demo available for download at the end of this article shows how to insert new records into the Northwind database's Products
table, allowing the user to supply the values for the new product's name, supplier, category, and price. These four values are stored in the Products
table's ProductName
, SupplierID
, CategoryID
, and UnitPrice
fields, respectively.The markup for the inserting interface (shown below) includes two TextBoxes - one for the
ProductName
field and one for UnitPrice
- and two DropDownLists - one forSupplierID
and one for CategoryID
. There's also two ImageButton controls that are the Insert and Cancel buttons. The Insert and Cancel buttons can be implemented as Button, LinkButton, or ImageButton controls, but they must have their CommandName
properties set to "Insert" and "Cancel", respectively.Finally, the markup below also includes the assignment of the
InsertItemPosition
to the value "FirstItem". This property can be set to "FirstItem", "LastItem", or "None". Setting it to "FirstItem" displays the inserting interface before any of the ListView's rendered items.<asp:ListView InsertItemPosition="FirstItem" ID="lvProducts" runat="server" DataSourceID="dsNorthwind"> |
As the markup above illustrates, the
InsertItemTemplate
can also include validation Web controls. The txtProductName
TextBox has a RequiredFieldValidator associated with it, as the ProductName
field is required, and the txtUnitPrice
TextBox has a CompareValidator to ensure that a non-negative, currency-formatted value is supplied.Validation With a ListView That Supports Inserting and Editing |
---|
The ListView used in this demo supports inserting, but does not support editing. However, it is possible to create a ListView that provides both inserting and editing functionality. If you create such a ListView and add validation controls to both the inserting and editing interfaces you may find that you cannot update a record until you "satisfy" the validators in the inserting interface. This is because by default ASP.NET checks all validation controls on the page when submitting. Long story short, even though the user is not inserting a record the Update button from the editing interface triggers the inserting-related validation controls to fire.The good news is that it's easy to partition the validation controls into separate validation groups - one for inserting and one for editing - which alleviates this issue. For more information on ASP.NET's validation controls and separating them into distinct groups, refer to Dissecting the Validation Controls in ASP.NET. |
Two-Way Databinding in the Inserting Interface
As discussed in the Editing Data installment we explored how to use ASP.NET's two-way databinding syntax to get the values entered by the user into the editing interface into the data source control's update parameters. In short, you use the
Bind
statement to both assign a value into a Web control property when the editing interface is displayed and to take the value of that property and send it back out to the update parameters when the Update button is clicked. For example, with a TextBox you'd use the Bind
statement on the Text
property like so:<asp:TextBox ID="ID" runat="server" Text='<%# Bind("columnName") %>' /> |
The inserting interface shown above includes
Bind
statements on the txtProductName
and txtUnitPrice
TextBox controls. When the user clicks the Insert button the ListView takes the values entered into these TextBoxes and puts them in the corresponding insert parameters in its data source control. You may have noticed that there are no Bind
statements on the DropDownLists. Usually you'd have a Bind
statement on the DropDownList's SelectedValue
property. However, if you are using ASP.NET version 3.5 and add such a Bind
statement you'll get the following error when visiting the page in a browser: System.InvalidOperationException: Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control.This behavior is a bug in the ListView control in ASP.NET version 3.5. According to Microsoft it will be fixed in ASP.NET version 4.0. In the meantime to work around it you need to do the following:
- Remove any
Bind
statements from the DropDownList controls in theInsertItemTemplate
- Create an event handler for the ListView's
ItemInserting
event, which fires after the user has clicked the Insert button but before the insert command is sent to the data source control - Programmatically reference the DropDownList control(s) in the
InsertItemTemplate
using the syntax:e.Item.FindControl("DDLcontrolID")
- Set the appropriate value(s) in the
e.Values
collection to theSelectedValue
property of the DropDownList control(s)
ItemInserting
event handler follows. Note that if you are using C# you would reference the Values
collection items using square brackets instead of parentheses, like: e.Values["CategoryID"] = ...
.Protected Sub lvProducts_ItemInserting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewInsertEventArgs) Handles lvProducts.ItemInserting |
With this code in place our ListView is complete! The user can visit the page, enter values into the TextBoxes and DropDownLists in the inserting interface, and click the Insert button to add a new record to the
Products
table.The screen shots below show the end user's experience as she adds a new product to the database. The first screen shot shows the inserting interface after the user has entered in the new product's information. The second screen shot shows the ListView after the user has clicked the Insert button. Note that the inserting interface is returned to its initial state and the ListView displays the just-added record.
Short-Circuiting the Inserting Workflow
In some scenarios you may want to cancel the inserting workflow based on the user's input or some other type of programmatic logic. Perhaps the range of values that a user can enter for the new product's price depend on the supplier or category, or maybe there are certain business rules that disallow certain supplier/category pairings.Whatever the rationale may be, you have an opportunity to examine the values to be inserted before the insert is committed via the
ItemInserting
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
ItemInserting
event handler is straightforward. It pulls the value entered into the ProductName
field via the e.Values
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. If the check passes then the values from the DropDownLists are assigned to the appropriate parameters in the Values
collection and a message is displayed informing the user that their product was added.Protected Sub lvProducts_ItemInserting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewInsertEventArgs) Handles lvProducts.ItemInserting |
The following screen shot shows the client-side messagebox that is displayed when the user attempts to add a new product with a 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 inserting capabilities to the ListView is relatively straightforward: create an inserting interface and set the ListView's
InsertItemPosition
property to either "FirstItem" or "LastItem", depending on where you want the inserting interface to appear. Keep in mind that in the inserting interface you cannot use two-way databinding to retrieve data from a DropDownList control; instead, you have to programmatically reference the DropDownLists and assign their SelectedValue
properties to the appropriate values in the Values
collection. This assignment can be performed from the ListView's ItemInserting
event handler. And that's it! The data source control handles the actual insert logic.