Фильтрация основных и подробных данных на двух страницах с помощью элемента управления Repeater и DataList (C#)

Скотт Митчелл

Загрузить PDF-файл

В этом руководстве мы рассмотрим, как разделить 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).

Настройка ObjectDataSource для использования метода GetCategories класса CategoriesBLL

Рис. 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. Каждая категория отображается как элемент маркированного списка (щелкните для просмотра полноразмерного изображения)

Чтобы пользователь отображал сведения для определенной категории, необходимо добавить ссылку на каждый элемент маркированного списка, который при щелчке перенастроит пользователя на вторую страницу (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 значение (Нет).

Настройка ObjectDataSource для использования метода GetProductsByCategoryID(categoryID) класса ProductsBLL

Рис. 4. Настройка ObjectDataSource для использования ProductsBLL метода класса GetProductsByCategoryID(categoryID) (щелкните для просмотра полноразмерного изображения)

GetProductsByCategoryID(categoryID) Так как метод принимает входной параметр (categoryID), мастер выбора источника данных позволяет указать источник параметра. Присвойте источнику параметра значение QueryString с помощью QueryStringField CategoryID.

Использование поля Querystring 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) .

Доступ к сведениям о категории с помощью метода GetCategoryByCategoryID(categoryID) класса CategoriesBLL

Рис. 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.