Советы и приемы при работе с ListView - Создание иерархического представления
ОГЛАВЛЕНИЕ
Создание иерархического представления
Для создания иерархического представления данных используется та же модель, что и для создания иерархического меню. В данном случае альтернативным вариантом будет использование элемента управления TreeView для многоуровневого представления данных. Однако привязка данных к элементу управления TreeView требует иерархического источника данных. Использование вложенных элементов управления ListView дает повышенную гибкость по отношению как к структуре источника данных, так и к получающемуся интерфейсу пользователя. Эти концепции стоит раскрыть.
Предположим, необходимо создать иерархическую таблицу данных, в которой клиенты, заказы и сведения о заказах отображаются соответственно текущим отношениям таблицы. Как тут получить данные и привязать их к элементу управления? Рассмотрите код на рис. 3. Для простой загрузки данных в объектную модель, удобную для хранения иерархии данных, можно использовать LINQ-SQL . Обратите внимание, что при выполнении запроса в LINQ-SQL на деле извлекаются только напрямую запрошенные данные. Другими словами, извлекается только первый уровень графа, связанные объекты не загружаются одновременно с ним.
Рис.3 Загрузка правильных данных
Public Class DataCache
{
public IEnumerable GetCustomers()
{
NorthwindDataContext db = new NorthwindDataContext();
DataLoadOptions opt = new DataLoadOptions();
opt.LoadWith<Customer>(c => c.Orders);
opt.LoadWith<Order>(o => o.Order_Details);
db.LoadOptions = opt;
var data = from c in db.Customers
select new { c.CompanyName, c.Orders };
return data.ToList();
}
public int GetCustomersCount()
{
// Return the number of customers
NorthwindDataContext db = new NorthwindDataContext();
return db.Customers.Count();
}
public IEnumerable GetCustomers(int maxRows, int startRowIndex)
{
if (maxRows < 0)
return GetCustomers();
NorthwindDataContext db = new NorthwindDataContext();
DataLoadOptions opt = new DataLoadOptions();
opt.LoadWith<Customer>(c => c.Orders);
opt.LoadWith<Order>(o => o.Order_Details);
db.LoadOptions = opt;
var data = (from c in db.Customers
select new {
c.CompanyName,
c.Orders
}).Skip(startRowIndex).Take(maxRows);
return data.ToList();
}
}
NorthwindDataContext db = new NorthwindDataContext();
DataLoadOptions opt = new DataLoadOptions();
opt.LoadWith<Customer>(c => c.Orders);
opt.LoadWith<Order>(o => o.Order_Details);
db.LoadOptions = opt;
Класс DataLoadOptions можно использовать для изменения поведения ядра LINQ-SQL, чтобы данные, на которые дается ссылка указанным отношением, загружались бы немедленно. Код на рис. 3 гарантирует, что заказы загружаются вместе с клиентами, а сведения – вместе с заказами.
Метод LoadWith загружает данные в соответствии с указанным отношением. Метод AssociateWith можно использовать для фильтрации предварительно выбранных связанных объектов следующим образом:
opt.AssociateWith<Customer>(
c => c.Orders.Where(o => o.OrderDate.Value.Year == 1997));
В данном примере при выборе данных клиента предварительно выбираются только заказы, сделанные в 1997 году. Когда необходимо предварительно выбрать связанные данные или применить фильтр, используется метод AssociateWith. Разработчик должен сам обеспечить отсутствие циклических ссылок между таблицами – например, при загрузке заказов для клиента, а затем загрузке клиента для заказа, как показано здесь:
DataLoadOptions opt = new DataLoadOptions();
opt.LoadWith<Customer> (c => c.Orders);
opt.LoadWith<Order> (o => o.Customer);
Теперь, когда все данные готовы, можно подумать и о привязке. В данном случае неплохо работает двухуровневый элемент управления ListView. ListView верхнего уровня привязывается к коллекции объектов Customer («Клиент»), а самый глубокий из вложенных элементов управления ListView – к свойству Orders («Заказы») каждого привязанного объекта Customer. В коде на рис. 4 показана разметка для трехуровневого иерархического представления, где клиенты отображаются на первом уровне и визуализируются свойством ItemTemplate внешнего элемента управления ListView. Затем внедренный элемент управления ListView привязывается к заказам. И, наконец, шаблон ItemTemplate встроенного элемента управления ListView содержит элемент управления GridView для перечисления сведений о каждом заказе.
Рис. 4 Трехуровневая иерархия
<asp:ListView ID="ListView1" runat="server"
DataSourceID="ObjectDataSource1"
ItemPlaceholderID="lvItemPlaceHolder">
<LayoutTemplate>
<asp:PlaceHolder runat="server" ID="lvItemPlaceHolder" />
</LayoutTemplate>
<ItemTemplate>
<asp:Panel runat="server" ID="panelCustomerInfo"
cssclass="customerInfo">
<%# Eval("CompanyName") %>
</asp:Panel>
<asp:panel runat="server" ID="panelCustomerDetails"
cssclass="customerDetails">
<asp:ListView runat="server"
DataSource='<%# Eval("Orders") %>'
ItemPlaceholderID="lvOrdersItemPlaceHolder">
<LayoutTemplate>
<ul>
<asp:PlaceHolder runat="server"
ID="lvOrdersItemPlaceHolder" />
</ul>
</LayoutTemplate>
<ItemTemplate>
<li>
Order #<%# Eval("OrderID") %>
<span class="orderDate">
placed on <%#
((DateTime)Eval("OrderDate")).ToString
("ddd, dd MMM yyyy") %>
</span>
<span class="orderEmployee">
managed by <b><%# Eval("Employee.LastName") %></b>
</span>
<asp:GridView runat="server"
DataSource='<%# Eval("Order_Details") %>'
SkinID="OrderDetailsGridSkin" >
</asp:GridView>
</li>
</ItemTemplate>
</asp:ListView>
</asp:panel>
</ItemTemplate>
</asp:ListView>