Фильтрация основных и подробных данных на двух страницах с помощью элемента управления Repeater и DataList (C#)
В этом руководстве мы рассмотрим, как разделить master/подробный отчет на две страницы. На странице "master" мы используем элемент управления Repeater для отрисовки списка категорий, которые, щелкнув, переведут пользователя на страницу сведений, где в списке данных из двух столбцов отображаются продукты, относящиеся к выбранной категории.
Введение
В предыдущем руководстве мы узнали, как отображать master/подробные отчеты на одной веб-странице с помощью DropDownLists для отображения записей master и DataList для отображения сведений. Еще один распространенный шаблон, используемый для master/подробных отчетов, заключается в том, что записи master на одной веб-странице и подробные сведения — на другой. В предыдущем руководстве фильтрация основных и подробных данных на двух страницах мы рассмотрели этот шаблон с помощью GridView для отображения всех поставщиков в системе. Этот GridView включал HyperLinkField, который отображался в виде ссылки на вторую страницу, передавая SupplierID
в строку запроса. На второй странице использовался GridView для перечисления продуктов, предоставляемых выбранным поставщиком.
Такие двухстраничные master/подробные отчеты также можно выполнять с помощью элементов управления DataList и Repeater. Единственное отличие заключается в том, что ни DataList, ни Repeater не поддерживают элемент управления HyperLinkField. Вместо этого необходимо добавить элемент управления HyperLink Web или элемент HTML привязки (<a>
) в элемент управления ItemTemplate
. Затем свойство HyperLink NavigateUrl
или атрибут привязки href
можно настроить с помощью декларативного или программного подхода.
В этом руководстве мы рассмотрим пример, в который выводится список категорий маркированного списка на одной странице с помощью элемента управления Repeater. Каждый элемент списка будет содержать имя и описание категории, а имя категории отображается в виде ссылки на вторую страницу. Щелкнув эту ссылку, пользователь перейдет на вторую страницу, где в DataList будут показаны продукты, которые относятся к выбранной категории.
Шаг 1. Отображение категорий в маркированных списках
Первым шагом при создании любого master/подробного отчета является отображение записей master. Поэтому наша первая задача — отобразить категории на странице "master". Откройте страницу CategoryListMaster.aspx
в папке DataListRepeaterFiltering
, добавьте элемент управления Repeater и выберите в смарт-теге новый объект ObjectDataSource. Настройте новый объект ObjectDataSource таким образом, чтобы он обращается к своим данным из CategoriesBLL
метода класса GetCategories
(см. рис. 1).
Рис. 1. Настройка ObjectDataSource для использования CategoriesBLL
метода класса GetCategories
(щелкните для просмотра полноразмерного изображения)
Затем определите шаблоны Repeater таким образом, чтобы каждое имя и описание категории отображались в виде элемента маркированного списка. Давайте пока не будем беспокоиться о наличии у каждой категории ссылки на страницу сведений. Ниже показана декларативная разметка для Repeater и ObjectDataSource.
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="ObjectDataSource1"
EnableViewState="False">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><%# Eval("CategoryName") %> - <%# Eval("Description") %></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
После завершения этой разметки просмотрите ход выполнения в браузере. Как показано на рисунке 2, ретранслятор отображается в виде маркированного списка с именем и описанием каждой категории.
Рис. 2. Каждая категория отображается как элемент маркированного списка (щелкните для просмотра полноразмерного изображения)
Шаг 2. Преобразование имени категории в ссылку на страницу сведений
Чтобы пользователь отображал сведения для определенной категории, необходимо добавить ссылку на каждый элемент маркированного списка, который при щелчке перенастроит пользователя на вторую страницу (ProductsForCategoryDetails.aspx
). На этой второй странице будут отображаться продукты для выбранной категории с помощью DataList. Чтобы определить категорию, ссылка на которую была нажата CategoryID
, необходимо передать категорию на вторую страницу с помощью некоторого механизма. Самый простой и простой способ передачи скалярных данных с одной страницы на другую — это строка запроса, которую мы будем использовать в этом руководстве. В частности, ProductsForCategoryDetails.aspx
страница ожидает, что выбранное categoryID
значение будет передано через поле строки запроса с именем CategoryID
. Например, чтобы просмотреть продукты для категории "Напитки", которая имеет CategoryID
значение 1, пользователь должен посетить ProductsForCategoryDetails.aspx?CategoryID=1
.
Чтобы создать гиперссылку для каждого элемента маркированного списка в Repeater, необходимо добавить элемент управления HyperLink Web или элемент привязки HTML (<a>
) в ItemTemplate
. В сценариях, где гиперссылка отображается одинаково для каждой строки, будет достаточно любого из них. Для repeaters я предпочитаю использовать элемент anchor. Чтобы использовать элемент привязки, обновите ItemTemplate элемента Repeater следующим образом:
<li>
<a href='ProductsForCategoryDetails.aspx?CategoryID=<%# Eval("CategoryID") %>'>
<%# Eval("CategoryName") %>
</a> - <%# Eval("Description") %>
</li>
Обратите внимание, что CategoryID
можно внедрить непосредственно в атрибут элемента href
привязки. Однако для этого обязательно разделите href
значение атрибута апострофами (и заметьте кавычки), так как Eval
метод в href
атрибуте разделяет свою строку ("CategoryID"
) кавычками. Кроме того, вместо него можно использовать веб-элемент управления HyperLink:
<li>
<asp:HyperLink runat="server" Text='<%# Eval("CategoryName") %>'
NavigateUrl='<%# "ProductsForCategoryDetails.aspx?CategoryID=" &
Eval("CategoryID") %>'>
</asp:HyperLink>
- <%# Eval("Description") %>
</li>
Обратите внимание, что статическая часть URL-адреса добавляется ProductsForCategoryDetails.aspx?CategoryID
к результату Eval("CategoryID")
непосредственно в синтаксисе привязки данных с помощью объединения строк.
Одним из преимуществ использования элемента управления HyperLink является то, что при необходимости к нему можно получить доступ программным способом из обработчика ItemDataBound
событий Repeater. Например, может потребоваться отобразить имя категории в виде текста, а не ссылки на категории без связанных продуктов. Такое проверка может выполняться программным способом в ItemDataBound
обработчике событий. Для категорий без связанных продуктов свойство HyperLink NavigateUrl
может иметь пустую строку, что приводит к отображению этого конкретного имени категории в виде обычного текста (а не ссылки). Дополнительные сведения о форматировании содержимого DataList и Repeater на основе данных см. в руководстве по форматированию содержимого DataList и Repeater на основе программной ItemDataBound
логики с помощью обработчика событий.
Если вы следите за этим, вы можете использовать элемент привязки или элемент управления HyperLink на странице. Независимо от подхода, при просмотре страницы в браузере каждое имя категории должно отображаться в виде ссылки на ProductsForCategoryDetails.aspx
, передавая применимое CategoryID
значение (см. рис. 3).
Рис. 3. Ссылка ProductsForCategoryDetails.aspx
на имена категорий (щелкните, чтобы просмотреть полноразмерное изображение)
Шаг 3. Перечисление продуктов, которые относятся к выбранной категории
Завершив CategoryListMaster.aspx
работу страницы, мы готовы обратить наше внимание на реализацию страницы ProductsForCategoryDetails.aspx
сведений. Откройте эту страницу, перетащите элемент DataList с панели элементов на Designer и задайте для его ID
свойства значение ProductsInCategory
. Затем в смарт-теге DataList выберите добавить на страницу объект ObjectDataSource, назвав его ProductsInCategoryDataSource
. Настройте его таким образом, чтобы он вызывает ProductsBLL
метод класса GetProductsByCategoryID(categoryID)
; установите для раскрывающихся списков на вкладках INSERT, UPDATE и DELETE значение (Нет).
Рис. 4. Настройка ObjectDataSource для использования ProductsBLL
метода класса GetProductsByCategoryID(categoryID)
(щелкните для просмотра полноразмерного изображения)
GetProductsByCategoryID(categoryID)
Так как метод принимает входной параметр (categoryID
), мастер выбора источника данных позволяет указать источник параметра. Присвойте источнику параметра значение QueryString с помощью QueryStringField CategoryID
.
Рис. 5. Использование поля Querystring в CategoryID
качестве источника параметра (щелкните для просмотра полноразмерного изображения)
Как мы видели в предыдущих руководствах, после завершения работы с мастером ItemTemplate
выбора источника данных Visual Studio автоматически создает для DataList, который перечисляет имя и значение каждого поля данных. Замените этот шаблон тем, который содержит только название продукта, поставщика и цену. Кроме того, задайте для свойства DataList RepeatColumns
значение 2. После этих изменений декларативная разметка DataList и ObjectDataSource должны выглядеть примерно так:
<asp:DataList ID="ProductsInCategory" runat="server" DataKeyField="ProductID"
RepeatColumns="2" DataSourceID="ProductsInCategoryDataSource"
EnableViewState="False">
<ItemTemplate>
<h5><%# Eval("ProductName") %></h5>
<p>
Supplied by <%# Eval("SupplierName") %><br />
<%# Eval("UnitPrice", "{0:C}") %>
</p>
</ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="ProductsInCategoryDataSource"
OldValuesParameterFormatString="original_{0}" runat="server"
SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL">
<SelectParameters>
<asp:QueryStringParameter Name="categoryID" QueryStringField="CategoryID"
Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
Чтобы просмотреть эту страницу в действии, начните со CategoryListMaster.aspx
страницы. Затем щелкните ссылку в маркированном списке категорий. При этом вы будете переходить к ProductsForCategoryDetails.aspx
, передавая CategoryID
через строка запроса. Объект ProductsInCategoryDataSource
ObjectDataSource в будет ProductsForCategoryDetails.aspx
получать только те продукты для указанной категории и отображать их в DataList, который отображает два продукта в каждой строке. На рисунке 6 показан снимок экрана при ProductsForCategoryDetails.aspx
просмотре напитков.
Рис. 6. Напитки отображаются, два на строку (щелкните для просмотра полноразмерного изображения)
Шаг 4. Отображение сведений о категории в ProductsForCategoryDetails.aspx
Когда пользователь щелкает категорию в CategoryListMaster.aspx
, он принимает ProductsForCategoryDetails.aspx
и отображает продукты, принадлежащие выбранной категории. Однако в ProductsForCategoryDetails.aspx
ней нет визуальных подсказок о том, какая категория была выбрана. Пользователь, который должен был щелкнуть Напитки, но случайно щелкнул Приправы, не может понять свою ошибку, как только он достигнет ProductsForCategoryDetails.aspx
. Чтобы устранить эту потенциальную проблему, в верхней части страницы можно отобразить сведения о выбранной ProductsForCategoryDetails.aspx
категории ( ее имя и описание).
Для этого добавьте FormView над элементом управления Repeater в ProductsForCategoryDetails.aspx
. Затем добавьте новый объект ObjectDataSource на страницу из смарт-тега FormView с именем CategoryDataSource
и настройте его для использования CategoriesBLL
метода класса GetCategoryByCategoryID(categoryID)
.
Рис. 7. Доступ к сведениям о категории с помощью CategoriesBLL
метода класса GetCategoryByCategoryID(categoryID)
(щелкните, чтобы просмотреть полноразмерное изображение)
Как и в ProductsInCategoryDataSource
случае с ObjectDataSource, добавленным на шаге 3, CategoryDataSource
мастер настройки источника данных запрашивает источник для GetCategoryByCategoryID(categoryID)
входного параметра метода. Используйте те же параметры, что и раньше, задав для параметра source значение QueryString, а для значения QueryStringField — CategoryID
значение (см. рис. 5).
После завершения работы мастера Visual Studio автоматически создает ItemTemplate
, EditItemTemplate
и InsertItemTemplate
для FormView. Так как мы предоставляем интерфейс только для чтения, вы можете удалить EditItemTemplate
и InsertItemTemplate
. Кроме того, вы можете настроить formView ItemTemplate
. После удаления лишних шаблонов и настройки ItemTemplate декларативная разметка FormView и ObjectDataSource должна выглядеть примерно так:
<asp:FormView ID="FormView1" runat="server" DataKeyNames="CategoryID"
DataSourceID="CategoryDataSource" EnableViewState="False" Width="100%">
<ItemTemplate>
<h3>
<asp:Label ID="CategoryNameLabel" runat="server"
Text='<%# Bind("CategoryName") %>' />
</h3>
<p>
<asp:Label ID="DescriptionLabel" runat="server"
Text='<%# Bind("Description") %>' />
</p>
</ItemTemplate>
</asp:FormView>
<asp:ObjectDataSource ID="CategoryDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategoryByCategoryID" TypeName="CategoriesBLL">
<SelectParameters>
<asp:QueryStringParameter Name="categoryID" Type="Int32"
QueryStringField="CategoryID" />
</SelectParameters>
</asp:ObjectDataSource>
На рисунке 8 показан снимок экрана при просмотре этой страницы в браузере.
Примечание
В дополнение к FormView я также добавил элемент управления HyperLink над FormView, который возвратит пользователя к списку категорий (CategoryListMaster.aspx
). Вы можете разместить эту ссылку в другом месте или вообще опустить ее.
Рис. 8. Сведения о категории теперь отображаются в верхней части страницы (щелкните, чтобы просмотреть полноразмерное изображение)
Шаг 5. Отображение сообщения, если продукты не относятся к выбранной категории
На CategoryListMaster.aspx
странице перечислены все категории в системе, независимо от того, есть ли связанные продукты. Если пользователь щелкает категорию без связанных продуктов, список данных в ProductsForCategoryDetails.aspx
не будет отображаться, так как его источник данных не будет содержать элементов. Как мы видели в предыдущих руководствах, GridView предоставляет EmptyDataText
свойство, которое можно использовать для указания текстового сообщения, отображаемого при отсутствии записей в источнике данных. К сожалению, ни DataList, ни Repeater не имеют такого свойства.
Чтобы отобразить сообщение, информирующее пользователя о том, что для выбранной категории нет подходящих продуктов, необходимо добавить элемент управления Метка на страницу, свойству которой Text
назначено сообщение для отображения в случае отсутствия соответствующих продуктов. Затем необходимо программно задать его Visible
свойство в зависимости от того, содержит ли DataList какие-либо элементы.
Для этого сначала добавьте метку под dataList. Задайте для свойства ID
значение NoProductsMessage
, а для свойства Text
— значение "Для выбранной категории нет продуктов..." Далее необходимо программно задать свойство Label Visible
в зависимости от того, были ли привязаны какие-либо данные к ProductsInCategory
DataList. Это назначение должно быть выполнено после привязки данных к DataList. Для GridView, DetailsView и FormView можно создать обработчик событий элемента управления DataBound
, который срабатывает после завершения привязки данных. Однако ни в DataList, ни в repeater нет доступных DataBound
событий.
В этом примере можно назначить свойство Label Visible
в Page_Load
обработчике событий, так как данные будут назначены DataList до события страницы Load
. Однако этот подход не будет работать в общем случае, так как данные из ObjectDataSource могут быть привязаны к DataList позже в жизненном цикле страницы. Например, если отображаемые данные основаны на значении в другом элементе управления, например при отображении master/подробного отчета с помощью DropDownList для хранения записей "master", данные могут не вернуться к веб-элементу управления данными до PreRender
этапа жизненного цикла страницы.
Одним из решений, которое будет работать во всех случаях, является назначение Visible
свойства False
в обработчике событий DataList ItemDataBound
(или ItemCreated
) при привязке типа Item
элемента или AlternatingItem
. В этом случае известно, что в источнике данных есть хотя бы один элемент данных, поэтому метка может быть скрыта NoProductsMessage
. В дополнение к этому обработчику событий нам также нужен обработчик событий для события DataList DataBinding
, где мы инициализируем Visible
свойство Label значением True
. DataBinding
Так как событие срабатывает до ItemDataBound
событий, свойству Label Visible
изначально будет присвоено значение True
; однако если есть какие-либо элементы данных, ему будет присвоено значение False
. Следующая логика реализуется в следующем коде:
protected void ProductsInCategory_DataBinding(object sender, EventArgs e)
{
// Show the Label
NoProductsMessage.Visible = true;
}
protected void ProductsInCategory_ItemDataBound(object sender, DataListItemEventArgs e)
{
// If we have a data item, hide the Label
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
NoProductsMessage.Visible = false;
}
Все категории в базе данных Northwind связаны с одним или несколькими продуктами. Чтобы протестировать эту функцию, я вручную настроил базу данных Northwind для этого руководства, переназначив все продукты, связанные с категорией «Продукция» (CategoryID
= 7), в категорию Морепродукты (CategoryID
= 8). Это можно сделать на сервере Обозреватель, выбрав Новый запрос и используя следующую UPDATE
инструкцию:
UPDATE Products SET
CategoryID = 8
WHERE CategoryID = 7
После соответствующего обновления базы данных вернитесь на страницу CategoryListMaster.aspx
и щелкните ссылку Произвести. Так как больше нет продуктов, относящихся к категории "Продукт", вы увидите сообщение "Нет продуктов для выбранной категории..." сообщение, как показано на рис. 9.
Рис. 9. Сообщение отображается, если нет продуктов, относящихся к выбранной категории (щелкните для просмотра полноразмерного изображения)
Сводка
Хотя master/подробные отчеты могут отображать master и подробные записи на одной странице, на многих веб-сайтах они разделены на две веб-страницы. В этом руководстве мы рассмотрели, как реализовать такой master/подробный отчет путем перечисления категорий в маркированный список с помощью repeater на веб-странице "master" и связанных продуктов, перечисленных на странице сведений. Каждый элемент списка на веб-странице master содержал ссылку на страницу сведений, передаваемую по значению строкиCategoryID
.
На странице сведений получение этих продуктов для указанного поставщика было выполнено с помощью ProductsBLL
метода класса GetProductsByCategoryID(categoryID)
. Значение categoryID
параметра было задано декларативно, используя CategoryID
значение querystring в качестве источника параметра. Мы также рассмотрели, как отображать сведения о категории на странице сведений с помощью FormView и как отображать сообщение, если не было продуктов, относящихся к выбранной категории.
Счастливое программирование!
Об авторе
Скотт Митчелл (Scott Mitchell), автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с Веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часа. Его можно связать по адресу mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.
Отдельная благодарность...
Эта серия учебников была проверена многими полезными рецензентами. Ведущие рецензенты этого руководства — Зак Джонс и Лиз Шулок. Хотите ознакомиться с моими предстоящими статьями MSDN? Если да, опустите мне строку в mitchell@4GuysFromRolla.com.
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по