[Disclaimer: Данная статья была переведена в рамках "Конкурса на лучший перевод статьи" на сервисе Quizful. Ссылка на оригинал находится внизу страницы.]
ListView - новый элемент управления в ASP.NET, представляющий собой шаблон-ориентированный слой для отображения данных и CRUD-операций над базами данных, и предлагающий нам весьма необычный способ конструирования веб-приложений, ориентированных на данные.
Любое пользовательское приложение, которое вы пишите, в той или иной степени нуждается в интеграции с данными. Как минимум, вам потребуется получать данные из таких источников, как реляционная БД или XML-файл, и осуществлять их форматирование перед выводом на экран. Невзирая на то, что в предыдущие версии ASP.NET уже были включены ориентированные на отображение данных (data-bound) элементы управления (напр. GridView), им недоставало обилия настроек и гибкости, так необходимых профессиональному веб-разработчику. Чтобы исправить данное положение, ASP.NET 3.5 снабдили новым элементом управления ListView, который предоставляет нам исключительную гибкость и настраиваемость, с помощью которых вы сможете максимально гибко форматировать данные, использовать шаблоны и стили, а также выполнять операции создания, чтения, обновления и удаления (CRUD) с минимумом кода.
Эта статья фокусируется на этапах доступа к данным, использующихся в новом элементе управления ListView, а также на таких продвинутых функциях ListView, как редактирование данных и обработка событий.
Введение в элемент управления ListView
Большая часть связанных с данными (data-bound) элементов управления, поставляемых с ASP.NET, автоматически огораживает выводимые данные дополнительной разметкой. Например, элемент управления GridView выводит данные на экран внутри HTML-таблицы (тег <table>), отображая каждую запись из связанного источника данных внутри табличной строки (тег <tr>), а каждое поле этой записи - внутри табличной ячейки (тег <td>). Несмотря на то, что вы можете использовать шаблон TemplateField и другие средства, предназначенные дла настройки внешнего вида GridView, вывод в любом случае будет заключен внутри табличного элемента. Но порой вам требуется осуществлять более полный контроль над оформлением вывода данных, чем HTML-разметка, формируемая связанными с данными элементами управления. И как раз в этом случае элемент управления ListView оказывается полезным. ListView не заключает выводимые на экран данные ни в какую дополнительную разметку. Вместо этого, отвественность за четкое определение выводимого HTML-кода лежит на вас. Вы самостоятельно и четко определяете разметку при помощи встроенных в ListView шаблонов. В Таблице №1 перечислены шаблоны, поддерживаемые элементом управления ListView.
Таблица 1. Шаблоны ListView
| Шаблон | Назначение |
| AlternatingItemTemplate | Определение различной разметки для чередующихся элементов с целью визуально подчеркнуть различия между идущими последовательно элементами. |
| EditItemTemplate | Определение отображения для находящихся в режиме редактирования элементов. |
| EmptyDataTemplate | Определение отображения для состояния ListView, когда связанный с ним источник не возвращает данных. |
| EmptyItemTemplate | Определение отображения для пустых элементов. |
| GroupSeparatorTemplate | Определение содержимого, отображаемого между группами элементов. |
| GroupTemplate | Назначение контейнерного объекта для содержимого; напр. табличная строка <tr>, <div> или <span>. |
| InsertItemTemplate | Назначение содержимого, отображаемого при вставке элемента пользователями. |
| ItemSeparatorTemplate | Определение содержимого, отображаемого между отдельными элементами. |
| ItemTemplate | Определение содержимого для отдельных элементов. |
| LayoutTemplate | Назначение корневого элемента, определяющего контейнерный объект (напр., <table>, <div> или <span>), в который будет заключено содержимое из шаблонов ItemTemplate и GroupTemplate. |
| SelectedItemTemplate | Назначение содержимого, отображаемого для выделенного в данный момент элемента. |
Двумя ключевыми шаблонами являются LayoutTemplate и ItemTemplate. В шаблоне с говорящим названием LayoutTemplate определяется вся разметка для элемента управления ListView, тогда как в ItemTemplate определяется разметка, используемая для отображения отдельной, привязанной к данным, записи. К примеру, следующий код выводит список элементов внутри HTML-таблицы:
<asp:ListView ID="..." runat="server" DataSourceID="...">
<LayoutTemplate>
<table …….>
<tr runat="server" ID="itemPlaceholder"></tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><%# Eval("Name") %></td>
</tr>
</ItemTemplate>
</asp:ListView>В указанном коде внутри шаблона LayoutTemplate у серверного элемента <tr> свойство ID выставлено в itemPlaceHolder. Это указывает ListView, что необходимо поместить сформированное внутри шаблона ItemTemplate содержимое внутрь таблицы. Это необходимо, поскольку шаблоны LayoutTemplate и ItemTemplate определяются отдельно друг от друга.
Простой пример привязки данных
Теперь, когда вы ознакомились с шаблонами ListView, следующим нашим шагом будет создание пробного веб-сайта. Назовите его ListViewExample (вы можете скачать пример отсюда). После создания веб-сайта, выберите в меню Website → Add New Item, чтобы создать новую страницу ASP.NET по имени SimpleListView.aspx (см. Листинг 1). На этой странице будет использован элемент управления ListView для отображения продуктов из таблицы Product, находящейся в пробной базе данных AdventureWorks.
<%@ Page Language="C#" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<link rel="Stylesheet" type="text/css" href="StyleSheet.css" />
<title>Simple Data Binding Example using ListView control</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ListView runat="server" ID="productsView"
DataSourceID="productSource" DataKeyNames="ProductID">
<LayoutTemplate>
<table cellpadding="2" runat="server" id="tblProducts"
style="width:460px">
<tr runat="server" id="itemPlaceholder">
</tr>
</table>
<asp:DataPager runat="server" ID="DataPager" PageSize="3">
<Fields>
<asp:NumericPagerField ButtonCount="10"
PreviousPageText="<--" NextPageText="-->" />
</Fields>
</asp:DataPager>
</LayoutTemplate>
<ItemTemplate>
<tr id="row" style="height:72px" runat="server">
<td valign="top" class="ProductInfo">
Product ID : <asp:Label ID="lblProductID" runat="server"
Text='<%#Eval("ProductID") %>' />
<br />
Name : <asp:Label ID="lblName" runat="server"
Text='<%#Eval("Name") %>' />
<br />
Product Number : <asp:Label ID="lblProductNumber"
runat="server" Text='<%#Eval("ProductNumber") %>' />
</td>
</tr>
</ItemTemplate>
<ItemSeparatorTemplate>
<tr id="separator" style="height:10px" runat="server">
<td>--------------------------------------------------------
------------------</td>
</tr>
</ItemSeparatorTemplate>
<EmptyDataTemplate>
There are no products!
</EmptyDataTemplate>
</asp:ListView>
<asp:SqlDataSource id="productSource" runat="server"
DataSourceMode="DataSet"
ConnectionString="<%$ ConnectionStrings:AdventureWorks%>"
SelectCommand="SELECT ProductID,Name,ProductNumber,
Color,ListPrice FROM Production.Product">
</asp:SqlDataSource>
</div>
</form>
</body>
</html>В Листинге 1 элемент управления SqlDataSource получает данные из таблицы Product при помощи параметров ConnectionString и SelectCommand, которым мы задаем соответствующие значения. Свойство ConnectionString получает строку подключения из файла web.config через выражение ASP.NET. На моей тестовой машине строка подключения в web.config определена следующим образом:
<connectionStrings>
<add name="AdventureWorks"
connectionString="server=localhost;uid=sa;
pwd=thiru;database=AdventureWorks;"/>
</connectionStrings>
Следующим шагом после указания свойств у SqlDataSource будет вывод этих данных через элемент управления ListView. В нашем случае разметка помещена в шаблон LayoutTemplate:
<LayoutTemplate>
<table cellpadding="2" runat="server" id="tblProducts"
style="width:460px">
<tr runat="server" id="itemPlaceholder">
</tr>
</table>
<asp:DataPager runat="server" ID="DataPager" PageSize="3">
<Fields>
<asp:NumericPagerField ButtonCount="10"
PreviousPageText="<--" NextPageText="-->" />
</Fields>
</asp:DataPager>
</LayoutTemplate>
В шаблоне LayoutTemplate мы определяем контейнер для вывода, формируемый элементом управления ListView. Кроме таблицы, в LayouteTemplate мы также указываем элемент управления <asp:DataPager>, который обеспечивает ListView функцией постраничной разбивки элементов. Элемент управления DataPager отображает все необходимые элементы управления, связанные с постраничной навигацией, и позволяет разбивать на страницы любые связанные с данными элементы управления, при условии, что они реализуют интерфейс IPageableItemContainer. ListView удовлетворяет этому условию.
Существуют два способа связать DataPager со связанным с данными элементом управления:
- Указать имя связанного с данными элемента управления в свойстве PagedControlID элемента управления DataPager
- Поместить DataPager внутрь связанного с данными элемента управления. В случае с ListView, вы можете поместить DataPager внутрь шаблона LayoutTemplate
Свойство PageSize у DataPager отвечает за количество отображаемых на каждой странице записей. Кроме того, вы можете изменить способ передачи номера текущей страницы серверу, воспользовавшись свойством QueryStringField.
Внутрь DataPager вы можете добавить элемент NumericPageField, который дает возможность пользователям перейти на необходимую страницу, просто выбрав ее номер.
<asp:NumericPagerField ButtonCount="10"
PreviousPageText="<--"
NextPageText="-->" />
Шаблон ItemTemplate позволяет указать разметку для любого элемента записи - вы можете запросить необходимую информацию из источника данных через метод Eval().
Редактирование данных с помощью ListView
Как вы успели убедиться, отображать данные через ListView совсем не сложно, но, кроме того, вы также легко можете позволить пользователям редактировать данные. Добавьте к нашему веб-сайту новую страницу ASP.NET с названием ListViewEditExample.aspx и модифицируйте ее код так, как показано в Листинге 2.
<%@ Page Language="C#" %>
<script runat="server">
void deptsView_ItemUpdated(object sender,
ListViewUpdatedEventArgs e)
{
lblResult.Text = e.AffectedRows.ToString() +
" row(s) successfully updated";
}
void deptsView_PagePropertiesChanged(object sender, EventArgs e)
{
//Set the text to empty when navigating to a different page
lblResult.Text = "";
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<link rel="Stylesheet" type="text/css" href="StyleSheet.css" />
<title>Editing Data using ListView Control</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ListView ID="ContactsListView" DataSourceID="deptSource"
DataKeyNames="DepartmentID" runat="server"
OnItemUpdated="deptsView_ItemUpdated"
OnPagePropertiesChanged="deptsView_PagePropertiesChanged">
<LayoutTemplate>
<table cellpadding="2" width="100%" border="1"
runat="server" id="tblProducts">
<tr id="row1" runat="server" class="header">
<th id="header2" runat="server">Name</th>
<th id="header3" runat="server">Group Name</th>
<th id="header1" runat="server">Action</th>
</tr>
<tr runat="server" id="itemPlaceholder" />
</table>
<asp:DataPager runat="server" ID="deptsDataPager" PageSize="3">
<Fields>
<asp:NextPreviousPagerField ShowFirstPageButton="True"
ShowLastPageButton="True" FirstPageText="|<< "
LastPageText=" >>|" NextPageText=" > "
PreviousPageText=" < " />
</Fields>
</asp:DataPager>
</LayoutTemplate>
<ItemTemplate>
<tr id="row2" runat="server">
<td>
<asp:Label ID="lblName" runat="Server" Text='<%#Eval("Name") %>' />
</td>
<td valign="top">
<asp:Label ID="lblGroupName" runat="Server"
Text='<%#Eval("GroupName") %>' />
</td>
<td>
<asp:LinkButton ID="btnEdit" runat="Server" Text="Edit"
CommandName="Edit" />
</td>
</tr>
</ItemTemplate>
<EditItemTemplate>
<tr style="background-color: #ADD8E6">
<td>
<asp:TextBox ID="txtName" runat="server"
Text='<%# Bind("Name") %>'
MaxLength="50" /><br />
</td>
<td>
<asp:TextBox ID="txtGroupName" runat="server" Text='<%#
Bind("GroupName") %>' MaxLength="50" /><br />
</td>
<td>
<asp:LinkButton ID="btnUpdate" runat="server"
CommandName="Update" Text="Update" />
<asp:LinkButton ID="btnCancel" runat="server"
CommandName="Cancel" Text="Cancel" />
</td>
</tr>
</EditItemTemplate>
</asp:ListView>
<asp:SqlDataSource ID="deptSource" runat="server"
ConnectionString="<%$ ConnectionStrings:AdventureWorks %>"
SelectCommand="SELECT [DepartmentID],[Name],[GroupName] FROM
HumanResources.Department" UpdateCommand="UPDATE
HumanResources.Department SET Name = @Name,
GroupName = @GroupName WHERE DepartmentID = @DepartmentID">
</asp:SqlDataSource>
<br /><br />
<asp:Label runat="server" ID="lblResult" Text=""
Font-Bold="true" />
</div>
</form>
</body>
</html>Код из Листинга 2 демонстрирует использование шаблона EditItemTemplate для формирования содержимого, используемого, когда элемент находится в режиме редактирования, и обновления информации в базе данных, через элемент управления SqlDataSource.
Для начала, пропишите в свойство UpdateCommand элемента управления SqlDataSource SQL-запрос, который будет выполняться для обновления базы данных последними значениями, указанными пользователем:
<asp:SqlDataSource ID="deptSource" runat="server"
ConnectionString="<%$ ConnectionStrings:AdventureWorks %>"
SelectCommand="SELECT [DepartmentID],[Name],[GroupName] FROM
HumanResources.Department" UpdateCommand="UPDATE
HumanResources.Department SET Name = @Name,
GroupName = @GroupName WHERE DepartmentID = @DepartmentID">
</asp:SqlDataSource>
Затем, в шаблоне ItemTemplate укажите ссылку, кликнув на которую пользователи смогут начать редактировать элемент:
<ItemTemplate>
----
----
<asp:LinkButton ID="btnEdit" runat="Server" Text="Edit"
CommandName="Edit" />
</td>
</tr>
</ItemTemplate>
После этого, создайте шаблон EditItemTemplate и объявите в нем текстовые поля, которые пользователь должен будет заполнить новыми значениями. В нашем случае, это название и групповое название отдела. Также добавьте в шаблон ссылки Update и Cancel, которые будут использоваться для обновления базы данных или отмены редактирования соответственно.
<EditItemTemplate>
<tr style="background-color: #ADD8E6">
<td>
<asp:TextBox ID="txtName" runat="server"
Text='<%# Bind("Name") %>'
MaxLength="50" /><br />
</td>
<td>
<asp:TextBox ID="txtGroupName" runat="server" Text='<%#
Bind("GroupName") %>' MaxLength="50" /><br />
</td>
<td>
<asp:LinkButton ID="btnUpdate" runat="server"
CommandName="Update" Text="Update" />
<asp:LinkButton ID="btnCancel" runat="server"
CommandName="Cancel" Text="Cancel" />
</td>
</tr>
</EditItemTemplate>
Управлять поведением элемента управления LinkButton вы можете установив свойство CommandName в соответствующее значение, как показано в Таблице 2.
Таблица 2. Допустимые значения свойства CommandName элемента управления LinkButton
| Значение | Пояснение |
| Cancel | Отменяет текущую операцию |
| Delete | Удаляет выбранный элемент из источника данных |
| Edit | Переводит выбранный элемент ListView в режим редактирования и отображает содержимое шаблона EditItemTemplate |
| Insert | Добавляет значения из ListView в источник данных в виде новой записи |
| Update | Обновляет источник данных новыми значениями из ListView |
После обновления элемент управления ListView инициирует событие OnItemUpdated, которое вы можете использовать для вывода информации, подтверждающей обновление. В Листинге 2 используются два события ListView:
- OnItemUpdated: Название говорит само за себя - данное событие позволяет вам выполнить собственный код после завершения операции обновления. В Листинге 2 данное событие используется для информирования пользователей о количестве обновленных записей.
- OnPagePropertiesChanged: ListView инициирует данное событие при изменении свойств страницы. В Листинге 2 данное событие используется для очистки текста, содержащегося в элементе управления Label.
Если ListView был настроен верно, то при открытии страницы в браузере вы должны будете увидеть что-то похожее на Рисунок 2.
Когда вы щелкнете по ссылке Edit, ListView воспользуется шаблоном EditItemTemplate для отображения текстовых полей, заполнение которых даст пользователям возможность обновить выбранный элемент. См. Рисунок 3.
Обратите внимание на ссылки Update и Cancel, отображаемые в правой колонке в режиме редактирования. Когда вы щелкаете по ссылке Update, чтобы сохранить изменения в базе данных, инициируется событие OnItemUpdated, в котором прописан вывод количества обновленных строк на экран. См. Рисунок 4 .
Вот и подошел к концу обзор ключевых возможностей элемента управления ListView. Вы ознакомились с примерами создания простой, работающей с данными веб-страницы, и более сложной страницы, где декларативно использовалась функциональность ListView по обновлению данных. В заключении мы узнали, как можно обрабатывать события, которые инициирует элемент управления ListView. Как видите, удивительная гибкость ListView позволяет легко управлять поведением и отображением данных, согласно вашим требованиям.
----------
Оригинальный текст статьи: Using the New ListView Control in ASP.NET 3.5