When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, June 10, 2009

Using ASP.NET 3.5's ListView and DataPager Controls: Editing Data

By Scott Mitchell


A Multipart Series on ASP.NET's ListView and DataPager Controls
This article is one in a series of articles on ASP.NET's ListView and DataPager controls, which were introduced with ASP.NET version 3.5.

  • Displaying Data with the ListView - looks at the ListView control basics, with demos on how to display data using the LayoutTemplate and ItemTemplate.
  • Grouping Data with the ListView Control - shows how to render different formatting or encasing markup to every N rendered records.
  • Sorting Data with the ListView Control - shows how to include buttons to sort the ListView's data.
  • Paging Through Data with the ListView and DataPager Controls - shows how to page through the ListView's data using the DataPager control.
  • Grouping By a Data Field - learn how to group the data in a ListView based on the actual data coming from the database.
  • Deleting Data - see how to delete the data bound to the ListView control.
  • Editing Data - learn how to edit the data bound to the ListView control.
  • Inserting Data - explore inserting new records directly from within the ListView control's interface.
  • Creating an SEO-Friendly Paging Interface - learn how to configure the DataPager to render an SEO-friendly paging interface.
  • The Ultimate DataPager Interface - create the ultimate DataPager interface using ASP.NET Routing.
  • 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!

    (It is assumed that the reader is familiar with how to edit data using a data source control. If this is not the case, please first read Accessing and Updating Data in ASP.NET: Updating Basics.)

    - continued -

    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.

    Clicking the Edit button shows an item's editing interface, which includes Update and Cancel buttons.

    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:

    1. The ListView raises its ItemEditing event.
    2. The ListView sets its EditIndex property to the index of the row whose Edit button was clicked.
    3. The ListView rebinds to its data source.
    4. 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:
    1. The ListView raises its ItemCanceling event.
    2. The ListView sets its EditIndex property to -1.
    3. The ListView rebinds to its data source.
    4. 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:
    1. The ListView raises its ItemUpdating event.
    2. The ListView assigns the values supplied in the editing interface to the update parameters for its associated data source control.
    3. The ListView assigns the key values for the row being updated to the update parameters for its associated data source control.
    4. The ListView calls its associated data source control's Update method, which actually performs the update.
    5. The ListView raises its ItemUpdated event handler.
    6. The ListView sets its EditIndex property to -1.
    7. 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".

    <asp:ListView ID="lvProducts" runat="server" DataSourceID="dsNorthwind" DataKeyNames="ProductID">
       ...
       
       <ItemTemplate>
          <h3>
             <%#Eval("ProductName")%>
             <asp:ImageButton ID="imgbEditProduct" runat="server" AlternateText="Edit Product"
                      ToolTip="Edit Product" CommandName="Edit" ImageUrl="~/Images/pencil.png" />

          </h3>
          <p>
             <b>Supplier:</b> <%#Eval("CompanyName")%><br />
             <b>Category:</b> <%#Eval("CategoryName")%><br />
             <b>Price:</b> <%#Eval("UnitPrice", "{0:c}")%>
          </p>
       </ItemTemplate>
    </asp:ListView>

    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:

    <asp:ListView ID="lvProducts" runat="server" DataSourceID="dsNorthwind" DataKeyNames="ProductID">
       ...
       
       <EditItemTemplate>
          <p>
             <b>Product Name:</b>
             <asp:TextBox ID="txtProductName" runat="server" Text='<%# Bind("ProductName") %>'></asp:TextBox>
             <asp:RequiredFieldValidator ID="rfvProductName" ControlToValidate="txtProductName" Display="Dynamic"
                                runat="server" ErrorMessage="[Required]"></asp:RequiredFieldValidator>
             <br />
             
             <b>Supplier:</b>
             <asp:DropDownList ID="ddlSuppliers" runat="server" DataSourceID="dsSuppliers" AppendDataBoundItems="true"
                   DataTextField="CompanyName" DataValueField="SupplierID"
                   SelectedValue='<%#Bind("SupplierID") %>'>
                <asp:ListItem Value="">None / Unknown</asp:ListItem>
             </asp:DropDownList>
             <br />
             
             <b>Category:</b>
             <asp:DropDownList ID="ddlCategories" runat="server" DataSourceID="dsCategories" AppendDataBoundItems="true"
                   DataTextField="CategoryName" DataValueField="CategoryID"
                   SelectedValue='<%#Bind("CategoryID") %>'>
                <asp:ListItem Value="">None / Unknown</asp:ListItem>
             </asp:DropDownList>
             <br />

             <b>Price:</b>
             $<asp:TextBox ID="txtUnitPrice" runat="server" Text='<%# Bind("UnitPrice", "{0:N2}") %>'></asp:TextBox>
             <asp:CompareValidator ID="cvUnitPrice" ControlToValidate="txtUnitPrice" runat="server"
                   ErrorMessage="[Invalid]" Operator="GreaterThanEqual" ValueToCompare="0" Type="Currency"></asp:CompareValidator>
             <br />
          </p>
          
          <p>
             <asp:ImageButton ID="imgbUpdateProduct" runat="server" ToolTip="Update Product" AlternateText="Update Product"
                         CommandName="Update" ImageUrl="~/Images/accept.png" />
             <asp:ImageButton ID="imgbCancelUpdate" runat="server" ToolTip="Cancel" AlternateText="Cancel"
                      CausesValidation="false" CommandName="Cancel" ImageUrl="~/Images/cancel.png" />

          </p>
       </EditItemTemplate>
    </asp:ListView>

    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!")

    Product names with more than three words are not permitted.

    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.

    Happy Programming!

  • By Scott Mitchell


    Further Readings:

  • Accessing and Updating Data in ASP.NET: Updating Basics
  • Accessing and Updating Data in ASP.NET: Customizing the Editing Interface
  • Accessing and Updating Data in ASP.NET: Handling Database NULL Values
  • Attachments


  • Download the Demo (in ZIP format)


  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article