Geeks With Blogs
Amit's Blog Sharing Thoughts and Learning

In my previous post, I have shown the data binding capabilities of ListView control. In this post, I will show the Data Editing power of ListView. Like the previous DataGrid, DataList and GridView controls the ListView control has the EditItemTemplate and it also comes up with the long awaited InsertItemTemplate, in the past there was a lot of attempt to allow the users to insert data through Header or Footer Template which is no longer required. In this post I will show you the full data editing capabilities of ListView which includes Insert, Edit and Delete with both LinqDataSource and code. We will follow the previous post example for the data editing.

The first thing you have to do to add the data editing capabilities is defining the Edit item and Insert item templates. Instead of row kind of style editing like the DataGrid and GridView we will follow the form style editing, this is the another powerful features of ListView that you have the full control on how the html is generated. The following shows the screen-shots of both EditItemTemplate and InsertItemTemplate view:

EditItemTemplate

InsertItemTemplate

The following shows the EditItem and InsertItem Template:

<EditItemTemplate>
    <tr>
        <td colspan="9">
            <table>
                <tbody>
                    <tr>
                        <th>
                            Company:
                        </th>
                        <td>
                            <asp:TextBox ID="CompanyNameTextBox" runat="server" Text='<% #Bind("CompanyName")%>' ValidationGroup="edit"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="CompanyValidator" runat="server" ControlToValidate="CompanyNameTextBox" ErrorMessage="<div>Company cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="edit"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Contact:
                        </th>
                        <td>
                            <asp:TextBox ID="ContactNameTextBox" runat="server" Text='<% #Bind("ContactName")%>' ValidationGroup="edit"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="ContactValidator" runat="server" ControlToValidate="ContactNameTextBox" ErrorMessage="<div>Contact cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="edit"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Title:
                        </th>
                        <td>
                            <asp:TextBox ID="ContactTitleTextBox" runat="server" Text='<% #Bind("ContactTitle")%>'></asp:TextBox>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Address:
                        </th>
                        <td>
                            <asp:TextBox ID="AddressTextBox" runat="server" TextMode="MultiLine" Columns="20" Rows="4" Text='<% #Bind("Address")%>' ValidationGroup="edit"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="AddressValidator" runat="server" ControlToValidate="AddressTextBox" ErrorMessage="<div>Address cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="edit"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            City:
                        </th>
                        <td>
                            <asp:TextBox ID="CityTextBox" runat="server" Text='<% #Bind("City")%>' ValidationGroup="edit"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="CityValidator" runat="server" ControlToValidate="CityTextBox" ErrorMessage="<div>City cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="edit"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Postal Code:
                        </th>
                        <td>
                            <asp:TextBox ID="PostalCodeTextBox" runat="server" Text='<% #Bind("PostalCode")%>' ValidationGroup="edit"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="PostalCodeValidator" runat="server" ControlToValidate="PostalCodeTextBox" ErrorMessage="<div>Postal code cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="edit"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Country:
                        </th>
                        <td>
                            <asp:TextBox ID="CountryTextBox" runat="server" Text='<% #Bind("Country")%>' ValidationGroup="edit"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="CountryValidator" runat="server" ControlToValidate="CountryTextBox" ErrorMessage="<div>Country cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="edit"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Phone:
                        </th>
                        <td>
                            <asp:TextBox ID="PhoneTextBox" runat="server" Text='<% #Bind("Phone")%>' ValidationGroup="edit"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="PhoneValidator" runat="server" ControlToValidate="PhoneTextBox" ErrorMessage="<div>Phone cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="edit"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th></th>
                        <td>
                            <asp:LinkButton ID="UpdateButton" CommandName="Save" runat="server" Text="Update" ValidationGroup="edit"></asp:LinkButton>
                            <asp:LinkButton ID="CancelButton" CommandName="Cancel" runat="server" Text="Cancel" CausesValidation="false"></asp:LinkButton>
                        </td>
                    </tr>
                </tbody>
            </table>
        </td>
    </tr>
</EditItemTemplate>
<InsertItemTemplate>
    <tr>
        <td colspan="9">
            <table>
                <tbody>
                    <tr>
                        <th>
                            ID:
                        </th>
                        <td>
                            <asp:TextBox ID="CustomerIDTextBox" runat="server" Text='<% #Bind("CustomerID")%>' ValidationGroup="add"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="IDValidator" runat="server" ControlToValidate="CustomerIDTextBox" ErrorMessage="<div>ID cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="add"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Company:
                        </th>
                        <td>
                            <asp:TextBox ID="CompanyNameTextBox" runat="server" Text='<% #Bind("CompanyName")%>' ValidationGroup="add"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="CompanyValidator" runat="server" ControlToValidate="CompanyNameTextBox" ErrorMessage="<div>Company cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="add"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Contact:
                        </th>
                        <td>
                            <asp:TextBox ID="ContactNameTextBox" runat="server" Text='<% #Bind("ContactName")%>' ValidationGroup="add"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="ContactValidator" runat="server" ControlToValidate="ContactNameTextBox" ErrorMessage="<div>Contact cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="add"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Title:
                        </th>
                        <td>
                            <asp:TextBox ID="ContactTitleTextBox" runat="server" Text='<% #Bind("ContactTitle")%>'></asp:TextBox>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Address:
                        </th>
                        <td>
                            <asp:TextBox ID="AddressTextBox" runat="server" Text='<% #Bind("Address")%>' TextMode="MultiLine" Columns="20" Rows="4" ValidationGroup="add"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="AddressValidator" runat="server" ControlToValidate="AddressTextBox" ErrorMessage="<div>Address cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="add"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            City:
                        </th>
                        <td>
                            <asp:TextBox ID="CityTextBox" runat="server" Text='<% #Bind("City")%>' ValidationGroup="add"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="CityValidator" runat="server" ControlToValidate="CityTextBox" ErrorMessage="<div>City cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="add"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Postal Code:
                        </th>
                        <td>
                            <asp:TextBox ID="PostalCodeTextBox" runat="server" Text='<% #Bind("PostalCode")%>' ValidationGroup="add"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="PostalCodeValidator" runat="server" ControlToValidate="PostalCodeTextBox" ErrorMessage="<div>Postal code cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="add"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Country:
                        </th>
                        <td>
                            <asp:TextBox ID="CountryTextBox" runat="server" Text='<% #Bind("Country")%>' ValidationGroup="add"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="CountryValidator" runat="server" ControlToValidate="CountryTextBox" ErrorMessage="<div>Country cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="add"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            Phone:
                        </th>
                        <td>
                            <asp:TextBox ID="PhoneTextBox" runat="server" Text='<% #Bind("Phone")%>' ValidationGroup="add"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="PhoneValidator" runat="server" ControlToValidate="PhoneTextBox" ErrorMessage="<div>Phone cannot be blank.</div>" SetFocusOnError="true" Display="Dynamic" ValidationGroup="add"></asp:RequiredFieldValidator>
                        </td>
                    </tr>
                    <tr>
                        <th></th>
                        <td>
                            <asp:LinkButton ID="InsertButton" CommandName="Insert" runat="server" Text="Save" ValidationGroup="add"></asp:LinkButton>
                            <asp:LinkButton ID="CancelButton" CommandName="Cancel" runat="server" Text="Cancel" CausesValidation="false"></asp:LinkButton>
                        </td>
                    </tr>
                </tbody>
            </table>
        </td>
    </tr>
</InsertItemTemplate>

To edit existing record, you have to put a Button in the ItemTemplate/AlternatingItemTemplate which commandName is set to Edit, you can also use ImageButton/LinkButton instead of regular button as in this example I am using LinkButton. The same holds true for deleting record, in this case the commandName has to be Delete. Next, in the EditItemTemplate you have to add buttons which commandName sets to Update and Cancel.

To add record, you must have to set the InsertItemTemplate position, the supported values are FirstItem, LastItem and None. Since we are using form view for adding record it does not look appealing showing it all the time, instead we will put a button in the LayoutTemplate, upon click the form view will appear at the end. Next, in the InsertItemTemplate two new buttons are required which commandName sets to Insert and Cancel. At last, as we are showing this template on the new button click, we need to put few lines of code to show/hide the template as well as the new button. The following shows the code:

private void CloseInsert()
{
    lvwCustomers.InsertItemPosition = InsertItemPosition.None;
    ((LinkButton) lvwCustomers.FindControl("NewButton")).Visible = true;
}

protected void NewButton_Click(object sender, EventArgs e)
{
    lvwCustomers.EditIndex = -1;
    lvwCustomers.InsertItemPosition = InsertItemPosition.LastItem;
    ((LinkButton) sender).Visible = false;
}

protected void lvwCustomers_ItemEditing(object sender, ListViewEditEventArgs e)
{
    CloseInsert();
}

protected void lvwCustomers_ItemCanceling(object sender, ListViewCancelEventArgs e)
{
    if (e.CancelMode == ListViewCancelMode.CancelingInsert)
    {
        CloseInsert();
    }
}

protected void lvwCustomers_ItemInserted(object sender, ListViewInsertedEventArgs e)
{
    CloseInsert();
}

That's it we are all set to Add/Edit/Delete the records with LinqDataSource control.

Now we will see how to do the same with code. It is almost same as the LinqDataSource except few things, we need to hook the ItemCommand event and add few empty event handlers, the following shows the code:

protected void lvwCustomers_ItemCommand(object sender, ListViewCommandEventArgs e)
{
    switch(e.CommandName)
    {
        case "Insert":
        {
            InsertCustomer(e.Item);
            break;
        }
        case "Update":
        {
            UpdateCustomer(e.CommandArgument as string, e.Item);
            break;
        }
        case "Delete":
        {
            DeleteCustomer(e.CommandArgument as string);
            break;
        }
    }
}

protected void lvwCustomers_ItemInserting(object sender, ListViewInsertEventArgs e)
{
}

protected void lvwCustomers_ItemEditing(object sender, ListViewEditEventArgs e)
{
    CloseInsert();
    lvwCustomers.EditIndex = e.NewEditIndex;
    BindList();
}

protected void lvwCustomers_ItemUpdating(object sender, ListViewUpdateEventArgs e)
{
}

protected void lvwCustomers_ItemCanceling(object sender, ListViewCancelEventArgs e)
{
    if (e.CancelMode == ListViewCancelMode.CancelingInsert)
    {
        CloseInsert();
    }
    else
    {
        lvwCustomers.EditIndex = -1;
    }

    BindList();
}

protected void lvwCustomers_ItemDeleting(object sender, ListViewDeleteEventArgs e)
{
}

As you can see that in ItemCommand event we are checking the commandName and based upon that we are calling the helper function which does the actual db operation. The reason behind having those empty event handlers like ItemInserting, ItemUpdating and ItemDeleting is, if those left unhandled you will get a nasty exception that the event was not handled. While playing with the ListView data editing my first try was these events to do the db operation instead of the ItemCommand, but found that the event argument always left empty(except the itemIndex) as well as the EditItem and InsertItem property of ListView if the ListView is not bind with any DataSource control.

Now lets see what those db operation functions does, the following shows the code:

private void InsertCustomer(ListViewItem insertItem)
{
    if (IsValid)
    {
        using (NorthwindDataContext db = new NorthwindDataContext())
        {
            Customer customer = new Customer();

            customer.CustomerID = ((TextBox)insertItem.FindControl("CustomerIDTextBox")).Text;
            customer.CompanyName = ((TextBox)insertItem.FindControl("CompanyNameTextBox")).Text;
            customer.ContactName = ((TextBox)insertItem.FindControl("ContactNameTextBox")).Text;
            customer.ContactTitle = ((TextBox)insertItem.FindControl("ContactTitleTextBox")).Text;
            customer.Address = ((TextBox)insertItem.FindControl("AddressTextBox")).Text;
            customer.City = ((TextBox)insertItem.FindControl("CityTextBox")).Text;
            customer.PostalCode = ((TextBox)insertItem.FindControl("PostalCodeTextBox")).Text;
            customer.Country = ((TextBox)insertItem.FindControl("CountryTextBox")).Text;
            customer.Phone = ((TextBox)insertItem.FindControl("PhoneTextBox")).Text;

            db.Customers.Add(customer);

            db.SubmitChanges();
            CloseInsert();
            BindList();
        }
    }
}

private void UpdateCustomer(string customerID, ListViewItem editItem)
{
    if (IsValid)
    {
        using (NorthwindDataContext db = new NorthwindDataContext())
        {
            Customer customer = db.Customers.Where(c => c.CustomerID == customerID).Single();

            customer.CompanyName = ((TextBox) editItem.FindControl("CompanyNameTextBox")).Text;
            customer.ContactName = ((TextBox)editItem.FindControl("ContactNameTextBox")).Text;
            customer.ContactTitle = ((TextBox)editItem.FindControl("ContactTitleTextBox")).Text;
            customer.Address = ((TextBox)editItem.FindControl("AddressTextBox")).Text;
            customer.City = ((TextBox)editItem.FindControl("CityTextBox")).Text;
            customer.PostalCode = ((TextBox)editItem.FindControl("PostalCodeTextBox")).Text;
            customer.Country = ((TextBox)editItem.FindControl("CountryTextBox")).Text;
            customer.Phone = ((TextBox)editItem.FindControl("PhoneTextBox")).Text;

            db.SubmitChanges();
            lvwCustomers.EditIndex = -1;
            BindList();
        }
    }
}

private void DeleteCustomer(string customerID)
{
    using(NorthwindDataContext db = new NorthwindDataContext())
    {
        Customer customer = db.Customers.Where(c => c.CustomerID == customerID).Single();
        db.Customers.Remove(customer);
        db.SubmitChanges();
    }

    Pager dpCustomers = (Pager)lvwCustomers.FindControl("dpCustomers");
    dpCustomers.CurrentPageNo = 1;

    BindList();
}

That's it. You will find the complete source code of both of this example in the bottom of this post. In my next post, I will show the new GroupTemplate of ListView.

Download: Full Source

kick it on DotNetKicks.com

Posted on Thursday, September 13, 2007 3:17 PM Asp.net , ListView | Back to top


Comments on this post: Asp.net ListView - Data Editing

# re: Asp.net ListView - Data Editing
Requesting Gravatar...
wasnt this all already present with the (almost identical) asp.net 1.1 datalist ? I fail to see whats so new and powerfull here
Left by Hakan on Sep 19, 2007 11:13 PM

# re: Asp.net ListView - Data Editing
Requesting Gravatar...
With DataList you cannot present the data in tabular format and allow the user to edit it in form view.
Left by Kazi Manzur Rashid on Sep 20, 2007 12:39 AM

# re: Asp.net ListView - Data Editing
Requesting Gravatar...
How would you get programmatic access to items in the EditItemTemplate? I need to set focus a control in there and I can't seem to find a handle to controls in that template. I've tried using findcontrol on the listview but it comes back as null.
Left by willis on Oct 31, 2007 6:15 AM

# re: Asp.net ListView - Data Editing
Requesting Gravatar...
I'm trying to get access controls in the EditItemTemplate of a list
view when the user edits an item. I need to set focus to a textbox in
this template after post back because the ListView is in a long
scrolling div. Without setting focus the user needs to scroll down the
div after postback to get to the item.

I've tried using listview.FindControl('tbxEdit') but this comes back
blank. Does anyone have any ideas?
Left by willis on Nov 01, 2007 6:01 AM

# re: Asp.net ListView - Data Editing
Requesting Gravatar...
Try using the ItemDataBound() event. Then use the ListViewItemEventArgs parameter to help:

e.Item.FindControl("XYZ")
Left by andy on Nov 30, 2007 9:49 AM

# re: Asp.net ListView - Data Editing
Requesting Gravatar...
I hope Somebody help me with source code vb with extention apx.vb but manual table not data grid
Left by mia on Jul 25, 2008 8:13 AM

# re: Asp.net ListView - Data Editing
Requesting Gravatar...
May I know how can this be acheived by using DataList.
Left by Padmaja on Sep 05, 2008 12:00 PM

# re: Asp.net ListView - Data Editing
Requesting Gravatar...
To get to an item in the Insert Template you can use this:

protected void ListView1_ItemCreated(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.InsertItem)
{
ListViewItem currentItem = (ListViewItem)e.Item;
TextBox TextBox = (TextBox)currentItem.FindControl("StartDateTextBox");
TextBox.Text = DateTime.Now.ToShortDateString();
}
}
Left by Michael Washington on Oct 31, 2008 4:46 AM

Your comment:
 (will show your gravatar)
 


Copyright © Kazi Manzur Rashid | Powered by: GeeksWithBlogs.net | Join free