ListView is a cool control in ASP.NET. It is usefull for - well - listing data.
Even cooler you can nest a ListView inside another ListView if you need to group your list into groups - e.g. log grouped by date or an OrderHeader -> OrderLines grouping - and it is easy.
Unfortunately editing nested items is a bit clumcy - and it took me some time to figure it out. I have made an example here with two nested ListViews.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="NesterListTest.WebForm1" EnableEventValidation="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ListView ID="ListView1" runat="server" DataKeyNames="Id" OnItemDataBound="BindNestedList">
<LayoutTemplate>
<table id="RegistrationLines">
<tr id="itemPlaceholder" runat="server"></tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr><th>OuterIndex: <%# Eval("Id") %></th></tr>
<asp:ListView ID="ListView2" runat="server" DataKeyNames="Id" OnItemEditing="EditNestedItem">
<ItemTemplate>
<tr>
<td><%# Eval("Value") %></td>
<td><asp:Button runat="server" ID="EditButton" CommandName="edit" Text="Edit" /></td>
</tr>
</ItemTemplate>
<EditItemTemplate>
<tr>
<td>Now editing -></td>
<td><%# Eval("Value") %></td>
</tr>
</EditItemTemplate>
</asp:ListView>
</ItemTemplate>
</asp:ListView>
</div>
</form>
</body>
</html>
In the Page_Load I just create some funke sample data. Note that I have two classes. These are just for holding the data - nothing else.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace NesterListTest
{
public partial class WebForm1 : System.Web.UI.Page
{
List<TestContainer> list;
protected void Page_Load(object sender, EventArgs e)
{
list = new List<TestContainer>();
for (int i = 0; i < 5; i++)
{
TestContainer tc = new TestContainer() { Id = i };
List<TestItem> l = new List<TestItem>();
for (int j = 0; j < i % 3; j++)
{
TestItem t = new TestItem() { Id = j, Value = "Cheese " + i + " > " + j };
l.Add(t);
}
tc.Items = l.ToArray();
list.Add(tc);
}
ListView1.DataSource = list;
ListView1.DataBind();
}
protected void BindNestedList(Object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
ListViewDataItem item = (ListViewDataItem)e.Item;
TestContainer container = (TestContainer)item.DataItem;
ListView innerList = (ListView)item.FindControl("ListView2");
innerList.DataSource = container.Items;
innerList.DataBind();
}
}
protected void EditNestedItem(Object sender, ListViewEditEventArgs e)
{
ListView lvs = sender as ListView;
ListViewDataItem ctl = (ListViewDataItem)ListView1.FindControl(lvs.Parent.ID);
if (ctl != null)
{
ListView lv = (ListView)ctl.FindControl("ListView2");
lv.EditIndex = e.NewEditIndex;
int indexOfParentControl = ListView1.Items.IndexOf(ctl);
TestContainer t = list[indexOfParentControl];
lv.DataSource = t.Items;
lv.DataBind();
}
}
}
public class TestContainer
{
public int Id { get; set; }
public TestItem[] Items { get; set; }
}
public class TestItem
{
public int Id { get; set; }
public string Value { get; set; }
}
}
In the EditNestedItem method, I find the parent control of the sender. As the sender is the inner ListView, the parent of this is a ListViewDataItem of the outer ListView. In the ListViewDataItem I find the inner ListView and set the EditIndex of it.
I then find the index of the ListViewDataItem in the outer ListViews items collection and now I have the index of the TestContainer for ListViewDataItem. Then I can grap it from the list and bind the Items of the TestContainer to the inner ListView.