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, May 27, 2009

Using ASP.NET 3.5's ListView and DataPager Controls: Deleting 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 previous installments in this article series have demonstrated how to display, group, sort, and page through data using the ListView control. In addition to displaying data, the ListView control also provides support for inserting, updating, and deleting data. If the ListView uses a data source control (such as a SqlDataSource or ObjectDataSource) and that data source control is configured to support insert, updating, or deleting, then implementing such functionality in the ListView does not require writing a single line of code. Rather, adding inserting and updating support entails creating templates that define the inserting and updating user interfaces and Button controls that trigger the actual update or insert. Implementing deleting support requires simply adding a properly configured Delete button to the ItemTemplate.

    This installment and the next explore how to perform inserts, updates, and deletes using the ListView control. This installment focuses on deleting and shows how to perform simple, standard deletes as well as more advanced deleting scenarios. The demos explored here (as well as the demos from previous installments) are 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 delete data using a data source control. If this is not the case, please first read Accessing and Updating Data in ASP.NET: Deleting Data.)

    - continued -

    An Overview of the ListView's Deleting Workflow


    A ListView control that supports deleting typically includes a Delete Button with each rendered item that, when clicked, deletes the associated item. For example, the screen shot below shows a ListView control that lists the customers from the Northwind database table. Each customer item includes the customer's name and contact information along with a "Delete Customer" button.

    Clicking the Delete Customer button deletes the specific customer.

    When the "Delete Customer" Button is clicked a postback ensues and the ListView begins its deleting workflow. This workflow proceeds as follows:

    1. The ListView raises its ItemDeleting event.
    2. The ListView assigns the key values for the row being deleted to the delete parameters for its associated data source control.
    3. The ListView calls its associated data source control's Delete method, which actually performs the delete.
    4. The ListView raises its ItemDeleted event handler.
    After the deletion workflow completes, the ListView re-retrieves the data from its data source control, which now no longer includes the just-deleted record.

    From the end user's perspective, the deleting workflow unfolds like this: the user clicks the "Delete Customer" button; there's a short pause and, whoosh, the selected customer is gone!

    Implementing Deleting in the ListView


    Adding deleting support to the ListView requires that the ListView's underlying data source control support deleting. 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 a DeleteCommand specified. If you are using an ObjectDataSource then you will need to have specified what object method to invoke to perform the delete. For more background on configuring the data source controls to support deleting, refer to Accessing and Updating Data in ASP.NET: Deleting Data.

    Recall that in order to kick off the deleting workflow there needs to be some Button control in the ItemTemplate that serves as the Delete 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 "Delete". For example, the demo available for download at the end of this article includes a ListView that displays records from the Northwind database's Customers table. The markup for the ItemTemplate displays the customer's CompanyName field in an <h3> element as well as the customer's contact person, location, and telephone number. There's also a Button control labeled "Delete Customer" that serves as the Delete Button. Note that its CommandName property is set to "Delete".

    <asp:ListView ID="lvCustomersDemo2" runat="server" DataSourceID="dsNorthwind" DataKeyNames="CustomerID">
       ...
       
       <ItemTemplate>
          <h3><%#Eval("CompanyName")%></h3>
          <p>
             <b>Contact:</b> <%#Eval("ContactName")%><br />
             <b>Location:</b> <%#Eval("City")%><br />
             <b>Tel:</b> <%#Eval("Phone")%>
          </p>
          
          <p>
             <asp:Button ID="btnDeleteCustomer" runat="server" Text="Delete Customer" CommandName="Delete" />
          </p>
       </ItemTemplate>
    </asp:ListView>

    Along with adding a Delete Button, it's also equally important that the ListView's DataKeyNames property be set to the column(s) that comprise the primary key. The Customers table's primary key is CustomerID. Therefore, in order for this ListView to correctly implement deleting it is imperative that its DataKeyNames property be set to CustomerID, as it is in the markup above. If this property is not set then the Delete Button, when clicked, will cause a postback but the record will not be deleted (as the data source control does not know the CustomerID value to delete).

    And... that's it! With the addition of a properly configured Delete Button and by setting the ListView's DataKeyNames field to the primary key we now have a ListView from which users can delete customers. That was easy.

    Debugging the Deleting Workflow
    When testing your ListView control, if you find that clicking the Delete Button does not actually delete the record, ensure that the GridView's DataKeyNames property is correctly set and that the Delete Button's CommandName property is set to "Delete".

    If you are deleting records from a database table that have associated records in a child table and if there's a foreign key constraint in the database (as their should be) you may get an exception if you delete a record that has children records. For example, the Customers table in the Northwind database has a one-to-many relationship with the Orders table. Consequently, if you try to delete a customer that has orders the Northwind database prohibits the delete as this violates the foreign key constraint and would orphan the order records for that customer. This foreign key constraint violation raised by the database manifests itself as an exception back in ASP.NET and the Yellow Screen of Death (YSOD) is displayed. One way to remedy this is to configure the foreign key constraint to cascade deletes, so that deleting a customer automatically deletes all of his orders. I modified the Northwind database to cascade deletes in this fashion.

    If you are getting some other error or unexpected behavior and have verified that the Delete Button's CommandName and the ListView's DataKeyNames properties are correctly set, you can always create an event handler for the ListView's ItemDeleting event and for the data source control's Deleting event. Set breakpoints in these event handlers and then, when hit, you can more closely inspect what, exactly, is happening.

    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 deleting capabilities of the data source control. Instead, you will need to create an event handler for the ListView's ItemDeleting event and implement your own deleting logic there.

    Enhancing the Deleting Interface To Include a Client-Side Confirmation


    The example we just examined implemented deleting but, perhaps, in a suboptimal way. Currently there's no confirmation when deleting a custom. If the user accidentally clicks the mouse while moving it over a "Delete Customer" button or if they click the incorrect "Delete Customer" button - poof - there's a postback, the customer record is deleted, and you have an angry user.

    This can be mitigated by requiring the user to confirm that they want to delete the record before it is actually deleted. There are a number of ways to do this, from taking the user to a separate page, to showing a client-side confirm dialog box, or through some custom client-side action. Perhaps the simplest way is to use a client-side confirm dialog box, which utilizes JavaScript's confirm function. The confirm function displays a modal dialog box that prompts the user to click "OK" or "Cancel", and returns a true or false value, respectively. In short, we can use the confirm function in a manner that cancels the postback if the user clicks the "Cancel" button. We just need to have the Delete Button's client-side onclick event handler return the value from the confirm function.

    The good news is that ASP.NET makes it easy to execute JavaScript when a Button is clicked. Just assign the JavaScript to the Button's OnClientClick property. The following markup shows the updated "Delete Customers" Button markup, which now has its OnClientClick property configured to use the confirm method.

    <asp:ListView ID="lvCustomersDemo2" runat="server" ...>
       ...
       
       <ItemTemplate>
          ...
          
          <p>
             <asp:Button ID="btnDeleteCustomer" runat="server" Text="Delete Customer" CommandName="Delete"
                         OnClientClick="return confirm('This will permanently delete this customer and all of their orders. Are you sure you want to do this!?!?');" />
          </p>
       </ItemTemplate>
    </asp:ListView>

    With this addition a client-side popup is displayed whenever the user clicks the "Delete Customer" button. If the user clicks the "Cancel" button then the postback is cancelled and the delete does not happen; however, if the user clicks "OK" then the postback continues and the customer is deleted.

    The user is prompted with a confirmation before the customer is deleted.

    Canceling the Delete Based On Programmatic Logic


    Recall that before the ListView control actually deletes the requested record it first raises its ItemDeleting event. This event signals that the ListView is right about to perform a delete and gives us an opportunity to cancel it, if needed. In certain scenarios there may be complex business logic that determines whether or not a particular record can be deleted. One way to enforce this business logic is to create an event handler for the ItemDeleting event and check to make sure that the record that is about to be deleted can, in fact, be deleted. If the record cannot be deleted then the workflow can be canceled and a message displayed to the user.

    Imagine that we wanted to prevent users from deleting customers with orders. One way to prevent this would be to not cascade deletes from the foreign key constraint, but imagine that the business rules were a bit more pervasive than that - maybe we wanted to let administrative users delete customers that have orders, but not let other users. Whatever the case, we could put a check in the ItemDeleting event handler and stop the delete if the customer being deleted has associated orders. The following code snippet shows an ItemDeleting event handler that implements this business rule:

    Protected Sub lvCustomersDemo3_ItemDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewDeleteEventArgs) Handles lvCustomersDemo3.ItemDeleting
       'Prohibit deletion of a customer who has records in the Orders table

       'First, determine the CustomerID of the customer being deleted
       Dim CustomerID As String = lvCustomersDemo3.DataKeys(e.ItemIndex).Value.ToString()

       'Now see how many records exist for this customer in Orders (if any)
       Using myConnection As New OleDbConnection(connectionString)
          Using myCommand As New OleDbCommand()
             myCommand.Connection = myConnection
             myCommand.CommandText = "SELECT COUNT(*) FROM [Orders] WHERE [CustomerID] = @CustomerID"
             myCommand.Parameters.AddWithValue("@CustomerID", CustomerID)

             'Issue the command
             myConnection.Open()
             Dim orderCount As Integer = Convert.ToInt32(myCommand.ExecuteScalar())
             myConnection.Close()

             'Are there more than zero orders?
             If orderCount > 0 Then
                e.Cancel = True    'Cancel the delete

                'Display a message
                ClientScript.RegisterStartupScript(Me.GetType(), "CannotDeleteScript", _
                                String.Format("alert('You cannot delete this customer because they have {0} orders on file.');", orderCount), _
                                True)
             End If
          End Using
       End Using
    End Sub

    The above code is certainly not an example of best practices as it has data access code directly in the ASP.NET code-behind class, but it does illustrate how to perform some programmatic check to determine whether or not to cancel the delete. The above code starts by determining the CustomerID value of the customer that is going to be deleted and does so by grabbing it from the ListView's DataKeys collection. Next, it connects to the database and sends a query that returns the number of records in the Orders table for this specific customer. If that number is greater than zero then the deleting workflow is cancelled (by setting the e.Cancel property to True) and a message is displayed to the user via the JavaScript alert function. (Alternatively, you could have displayed such a message in a Label Web control.)

    The net result is that if the user attempts to delete a customer that has orders the delete action is stopped and the user is displayed a message explaining why the could not delete that customer.

    If the user attempts to delete a customer with orders the delete is canceled and the user is shown a message as to why the delete cannot be performed.

    Conclusion


    In addition to displaying data, the ListView control can also provide an interface for deleting data. Building a ListView that supports deleting involves adding a Delete Button to the ItemTemplate - namely, a Button control with its CommandName property set to "Delete" - and assigning the ListView's DataKeyNames property to the primary key name(s). When a user visiting the page clicks the Delete Button a postback ensues and the ListView's deleting workflow unfolds. Prior to deleting the record the ListView fires its ItemDeleting event handler. As we saw in this article, you can create an event handler for this event and cancel the workflow, if needed.

    In addition to supporting deletes, the ListView also offers functionality for inserts and updates. We'll see how to insert and update data through the ListView in the next two installments.

    Happy Programming!

  • By Scott Mitchell


    Further Readings:

  • Accessing and Updating Data in ASP.NET: Deleting Data
  • JavaScript's confirm function
  • Attachments


  • Download the Demo (in ZIP format)


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