Отчет "Основной/подробности" с использованием маркированного списка основных записей с элементом управления DataList для подробных сведений (C#)

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

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

В этом руководстве мы сожмем двухстраничный отчет master/detail предыдущего руководства в одну страницу, отображая маркированный список имен категорий в левой части экрана и продукты выбранной категории в правой части экрана.

Введение

В предыдущем руководстве мы рассмотрели, как разделить master/подробный отчет на две страницы. На странице master мы использовали элемент управления Repeater для отображения маркированного списка категорий. Каждое имя категории было гиперссылкой, которая при щелчке переназначила пользователя на страницу сведений, где в списке данных из двух столбцов отображались продукты, относящиеся к выбранной категории.

В этом руководстве мы сожмем двухстраничный учебник в одну страницу, отображая маркированный список имен категорий в левой части экрана, где каждое имя категории отображается как LinkButton. Щелчок одного из имен категории LinkButtons вызывает обратную передачу и привязывает продукты выбранной категории к списку данных из двух столбцов в правой части экрана. Помимо отображения имен каждой категории, в поле Repeater слева отображается общее количество продуктов для данной категории (см. рис. 1).

Имя категории и общее количество продуктов отображаются слева

Рис. 1. Имя категории и Общее количество продуктов отображаются слева (щелкните для просмотра полноразмерного изображения)

Шаг 1. Отображение ретранслятора в левой части экрана

Для работы с этим руководством необходимо, чтобы маркированный список категорий отображался слева от выбранных продуктов категории. Содержимое веб-страницы можно размещать с помощью стандартных тегов абзаца элементов HTML, неразрывных пробелов, <table> s и т. д. или с помощью методов каскадной таблицы стилей (CSS). Все наши руководства до сих пор использовали методы CSS для позиционирования. При создании пользовательского интерфейса навигации на странице master в руководстве по основным страницам и навигации сайтов мы использовали абсолютное позиционирование, указывая точное смещение пикселей для списка навигации и содержимого main. Кроме того, css можно использовать для размещения одного элемента справа или слева от другого посредством плавающей операции. Маркированный список категорий может отображаться слева от продуктов выбранной категории, перемещая ретранслятор слева от DataList.

Откройте страницу CategoriesAndProducts.aspx из DataListRepeaterFiltering папки и добавьте на нее ретранслятор и DataList. Задайте для параметра Repeater s ID значение , Categories а для DataList — значение CategoryProducts. Перейдите в представление Источник и поместите элементы управления Repeater и DataList в собственные <div> элементы. То есть сначала заключите Repeater в <div> элемент, а затем DataList в собственный <div> элемент непосредственно после repeater. На этом этапе разметка должна выглядеть примерно так:

<div>
    <asp:Repeater ID="Categories" runat="server">
    </asp:Repeater>
</div>
<div>
    <asp:DataList ID="CategoryProducts" runat="server">
    </asp:DataList>
</div>

Чтобы переплыть ретранслятор слева от DataList, необходимо использовать атрибут стилей float CSS следующим образом:

<div>
    Repeater
</div>
<div>
    DataList
</div>

Перемещает float: left; первый <div> элемент слева от второго. Параметры width и padding-right указывают первые <div>width значения и количество добавленных полей между <div> содержимым элемента и его правым полем. Дополнительные сведения о плавающих элементах в CSS проверка floatutorial.

Вместо того, чтобы указывать параметр стиля непосредственно с помощью атрибута первого <p> элемента, давайте создадим новый класс CSS в Styles.css с именем FloatLeft:style

.FloatLeft
{
    float: left;
    width: 33%;
    padding-right: 10px;
}

Затем можно заменить на <div><div class="FloatLeft">.

После добавления класса CSS и настройки разметки на CategoriesAndProducts.aspx странице перейдите к Designer. Вы должны увидеть повторитель, плавающий слева от DataList (хотя сейчас они отображаются как серые поля, так как мы еще не настроили их источники данных или шаблоны).

Ретранслятор перемещается слева от DataList.

Рис. 2. Ретранслятор находится слева от DataList (Щелкните для просмотра полноразмерного изображения)

Шаг 2. Определение количества продуктов для каждой категории

После завершения разметки Repeater и DataList мы готовы привязать данные категории к элементу управления Repeater. Однако, как показано в маркированных списках категорий на рис. 1, в дополнение к имени каждой категории необходимо также отобразить количество продуктов, связанных с категорией. Чтобы получить доступ к этой информации, мы можем:

  • Определите эти сведения из класса кода программной части страницы ASP.NET. Учитывая конкретное categoryID , мы можем определить количество связанных продуктов, вызвав ProductsBLL метод класса s GetProductsByCategoryID(categoryID) . Этот метод возвращает объект , ProductsDataTable свойство которого Count указывает, сколько ProductsRow объектов существует, то есть количество продуктов для указанного categoryIDобъекта . Мы можем создать ItemDataBound обработчик событий для repeater, который для каждой категории, привязанной к Repeater, вызывает ProductsBLL метод класса s GetProductsByCategoryID(categoryID) и включает его количество в выходные данные.
  • Обновите CategoriesDataTable в типизированном наборе данных, чтобы включить столбец NumberOfProducts . Затем мы можем обновить GetCategories() метод в , CategoriesDataTable чтобы включить эти сведения, или оставить GetCategories() как есть и создать новый CategoriesDataTable метод с именем GetCategoriesAndNumberOfProducts().

Рассмотрим оба этих метода. Первый подход проще реализовать, так как нам не нужно обновлять уровень доступа к данным. однако для этого требуется больше взаимодействия с базой данных. Вызов ProductsBLL метода класса в GetProductsByCategoryID(categoryID) обработчике ItemDataBound событий добавляет дополнительный вызов базы данных для каждой категории, отображаемой в repeater. При использовании этого метода существует N + 1 вызовов базы данных, где N — это количество категорий, отображаемых в ретрансляторе. При втором подходе возвращается количество продуктов с информацией о каждой категории из CategoriesBLL метода класса s GetCategories() (или GetCategoriesAndNumberOfProducts()), что приводит к одному переходу к базе данных.

Определение количества продуктов в обработчике событий ItemDataBound

Определение количества продуктов для каждой категории в обработчике событий Repeater ItemDataBound не требует каких-либо изменений существующего уровня доступа к данным. Все изменения можно вносить непосредственно на CategoriesAndProducts.aspx странице. Начните с добавления нового объекта ObjectDataSource с именем с помощью CategoriesDataSource смарт-тега Repeater. Затем настройте CategoriesDataSource ObjectDataSource таким образом, чтобы он извлек свои данные из CategoriesBLL метода класса s GetCategories() .

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

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

Каждый элемент в Categories ретрансляторе должен быть щелкаемым, и при щелчке CategoryProducts dataList должен отображать эти продукты для выбранной категории. Это можно сделать, сделав каждую категорию гиперссылкой, ссылающейся на ту же страницу (CategoriesAndProducts.aspx), но передавая CategoryID через строку запроса, как мы видели в предыдущем руководстве. Преимущество этого подхода заключается в том, что поисковая система может добавлять и индексировать страницу, отображающую продукты определенной категории.

Кроме того, мы можем сделать каждую категорию LinkButton, которая будет использоваться в этом руководстве. LinkButton отображается в браузере пользователя в виде гиперссылки, но при щелчке вызывает обратную передачу; при обратной отправке необходимо обновить Объект DataList, чтобы отобразить продукты, относящиеся к выбранной категории. В этом руководстве использование гиперссылки имеет больше смысла, чем linkButton; Однако могут быть и другие сценарии, в которых использование LinkButton является более выгодным. Хотя подход с гиперссылками был бы идеальным для этого примера, давайте рассмотрим вместо этого с помощью LinkButton. Как мы увидим, использование LinkButton сопряжено с некоторыми проблемами, которые в противном случае не возникали бы при гиперссылке. Таким образом, использование LinkButton в этом руководстве позволит выделить эти проблемы и предоставить решения для тех сценариев, в которых вместо гиперссылки может потребоваться использовать LinkButton.

Примечание

Рекомендуется повторить это руководство с помощью элемента управления HyperLink или <a> элемента вместо LinkButton.

В следующей разметке показан декларативный синтаксис для Repeater и ObjectDataSource. Обратите внимание, что шаблоны Repeater отображают маркированный список с каждым элементом в виде LinkButton:

<asp:Repeater ID="Categories" runat="server" DataSourceID="CategoriesDataSource">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
    <ItemTemplate>
        <li><asp:LinkButton runat="server" ID="ViewCategory" /></li>
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

Примечание

Для работы с этим учебником для repeater должно быть включено состояние просмотра (обратите внимание на пропуск EnableViewState="False" элемента из декларативного синтаксиса Repeater). На шаге 3 мы создадим обработчик событий для события Repeater ItemCommand , в котором мы будем обновлять коллекцию ObjectDataSource SelectParameters DataList. Однако повторитель ItemCommandне срабатывает, если состояние представления отключено.

Свойство LinkButton со значением IDViewCategory свойства не задано Text . Если бы мы просто хотели отобразить имя категории, мы бы задали свойство Text декларативно с помощью синтаксиса привязки данных следующим образом:

<asp:LinkButton runat="server" ID="ViewCategory"
    Text='<%# Eval("CategoryName") %>' />

Тем не менее, мы хотим отобразить как имя категории, так и количество продуктов, относящихся к этой категории. Эти сведения можно получить из обработчика ItemDataBound событий Repeater, выполнив вызов ProductBLL метода класса s GetCategoriesByProductID(categoryID) и определив, сколько записей возвращается в результирующем ProductsDataTableобъекте , как показано в следующем коде:

protected void Categories_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    // Make sure we're working with a data item...
    if (e.Item.ItemType == ListItemType.Item ||
        e.Item.ItemType == ListItemType.AlternatingItem)
    {
        // Reference the CategoriesRow instance bound to this RepeaterItem
        Northwind.CategoriesRow category =
            (Northwind.CategoriesRow) ((System.Data.DataRowView) e.Item.DataItem).Row;
        // Determine how many products are in this category
        NorthwindTableAdapters.ProductsTableAdapter productsAPI =
            new NorthwindTableAdapters.ProductsTableAdapter();
        int productCount =
            productsAPI.GetProductsByCategoryID(category.CategoryID).Count;
        // Reference the ViewCategory LinkButton and set its Text property
        LinkButton ViewCategory = (LinkButton)e.Item.FindControl("ViewCategory");
        ViewCategory.Text =
            string.Format("{0} ({1:N0})", category.CategoryName, productCount);
    }
}

Сначала мы убедимся, что переработаем с элементом данных (который ItemType имеет значение Item или AlternatingItem), а затем ссылаемся на CategoriesRow экземпляр, который только что был привязан к текущему RepeaterItem. Затем мы определяем количество продуктов для этой категории, создав экземпляр ProductsBLL класса , вызвав его GetCategoriesByProductID(categoryID) метод и определив количество записей, возвращаемых с помощью Count свойства . Наконец, ViewCategory элемент LinkButton в ItemTemplate является ссылками, а его Text свойство имеет значение CategoryName (NumberOfProductsInCategory), где NumberOfProductsInCategory отформатировано в виде числа с нулем десятичных разрядов.

Примечание

Кроме того, мы могли бы добавить функцию форматирования в класс кода программной части страницы ASP.NET, который принимает значения категории CategoryName и CategoryID и возвращает CategoryName сцепленное с количеством продуктов в категории (как определено путем вызова GetCategoriesByProductID(categoryID) метода ). Результаты такой функции форматирования можно декларативно назначить свойству Text linkButton, заменив необходимость в обработчике ItemDataBound событий. Дополнительные сведения об использовании функций форматирования см. в руководствах Использование templateFields в элементе управления GridView или Форматирование DataList и Repeater Based On Data .

После добавления этого обработчика событий проверьте страницу в браузере. Обратите внимание, что каждая категория указана в маркированных списках, отображая имя категории и количество продуктов, связанных с этой категорией (см. рис. 4).

Отображаются имя и количество продуктов каждой категории

Рис. 4. Отображаются имя и количество продуктов каждой категории (щелкните для просмотра полноразмерного изображения)

CategoriesDataTableОбновление иCategoriesTableAdapterдля включения количества продуктов для каждой категории

Вместо того, чтобы определять количество продуктов для каждой категории, привязанной к ретранслятору, мы можем упростить этот процесс, настроив CategoriesDataTable и CategoriesTableAdapter в уровне доступа к данным, чтобы включить эти сведения в собственном коде. Для этого необходимо добавить новый столбец в для CategoriesDataTable хранения количества связанных продуктов. Чтобы добавить новый столбец в dataTable, откройте типизированный набор данных (App_Code\DAL\Northwind.xsd), щелкните правой кнопкой мыши dataTable, который нужно изменить, и выберите Добавить / Столбец. Добавьте новый столбец в ( CategoriesDataTable см. рис. 5).

Добавление нового столбца в CategoriesDataSource

Рис. 5. Добавление нового столбца в CategoriesDataSource (щелкните для просмотра полноразмерного изображения)

Будет добавлен новый столбец с именем Column1, который можно изменить, просто введя другое имя. Переименуйте этот новый столбец в NumberOfProducts. Далее необходимо настроить свойства этого столбца. Щелкните новый столбец и перейдите к окно свойств. Измените свойство столбца DataType с System.String на System.Int32 и задайте для ReadOnly свойства значение True, как показано на рис. 6.

Задание свойств DataType и ReadOnly нового столбца

Рис. 6. Задание DataType свойств и ReadOnly для нового столбца

CategoriesDataTable Хотя теперь имеет NumberOfProducts столбец, его значение не задается ни в одном из соответствующих запросов TableAdapter. Мы можем обновить GetCategories() метод для возврата этих сведений, если мы хотим, чтобы такие сведения возвращались при каждом получении сведений о категории. Однако если нам нужно получить только количество связанных продуктов для категорий в редких случаях (например, только для этого руководства), мы можем оставить GetCategories() "как есть" и создать новый метод, который возвращает эти сведения. Давайте воспользуемся последним подходом, создав новый метод с именем GetCategoriesAndNumberOfProducts().

Чтобы добавить этот новый GetCategoriesAndNumberOfProducts() метод, щелкните правой кнопкой CategoriesTableAdapter мыши и выберите пункт Создать запрос. Откроется мастер настройки запросов TableAdapter, который мы неоднократно использовали в предыдущих руководствах. Для этого метода запустите мастер, указав, что запрос использует нерегламентированную инструкцию SQL, которая возвращает строки.

Создание метода с помощью нерегламентированной инструкции SQL

Рис. 7. Создание метода с помощью нерегламентированной инструкции SQL (щелкните для просмотра полноразмерного изображения)

Инструкция SQL возвращает строки

Рис. 8. Инструкция SQL возвращает строки (щелкните для просмотра полноразмерного изображения)

На следующем экране мастера появится запрос для использования. Чтобы вернуть поля каждой CategoryIDкатегории , CategoryNameи Description , а также количество продуктов, связанных с категорией, используйте следующую SELECT инструкцию:

SELECT CategoryID, CategoryName, Description,
       (SELECT COUNT(*) FROM Products p WHERE p.CategoryID = c.CategoryID)
            as NumberOfProducts
FROM Categories c

Указание запроса для использования

Рис. 9. Указание запроса для использования (щелкните для просмотра полноразмерного изображения)

Обратите внимание, что вложенный запрос, вычисляющий количество продуктов, связанных с категорией, имеет псевдоним NumberOfProducts. Это соответствие именования приводит к тому, что значение, возвращаемое этим вложенным запросом, будет связано со столбцом CategoriesDataTable s NumberOfProducts .

После ввода этого запроса последним шагом является выбор имени для нового метода. Используйте FillWithNumberOfProducts и GetCategoriesAndNumberOfProducts для шаблонов Fill a DataTable и Return a DataTable соответственно.

Назовите методы New TableAdapter FillWithNumberOfProducts и GetCategoriesAndNumberOfProducts

Рис. 10. Назовите методы FillWithNumberOfProducts new TableAdapter и GetCategoriesAndNumberOfProducts (Щелкните для просмотра полноразмерного изображения)

На этом этапе уровень доступа к данным был расширен, включив в него количество продуктов в каждой категории. Так как весь наш уровень представления направляет все вызовы к DAL через отдельный уровень бизнес-логики, необходимо добавить соответствующий GetCategoriesAndNumberOfProducts метод в CategoriesBLL класс :

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Select, false)]
public Northwind.CategoriesDataTable GetCategoriesAndNumberOfProducts()
{
    return Adapter.GetCategoriesAndNumberOfProducts();
}

После завершения DAL и BLL мы готовы привязать эти данные к Categories repeater в CategoriesAndProducts.aspx! Если вы уже создали объект ObjectDataSource для repeater из раздела Определение количества продуктов в ItemDataBound обработчике событий, удалите этот объект ObjectDataSource и удаляйте параметр свойства Repeater DataSourceID , а также отсоедините событие Repeater от обработчика ItemDataBound событий, удалив Handles Categories.OnItemDataBound синтаксис в классе ASP.NET кода программной части.

Вернув repeater в исходное состояние, добавьте новый объект ObjectDataSource с именем с помощью CategoriesDataSource смарт-тега Repeater. Настройте ObjectDataSource для использования CategoriesBLL класса , но вместо GetCategories() использования метода GetCategoriesAndNumberOfProducts() ( см. рис. 11).

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

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

Затем обновите ItemTemplate , чтобы свойство LinkButton было декларативно Text назначено с помощью синтаксиса привязки данных и включает CategoryName поля данных и NumberOfProducts . Ниже приведена полная декларативная разметка CategoriesDataSource для Repeater и ObjectDataSource:

<asp:Repeater ID="Categories" runat="server" DataSourceID="CategoriesDataSource">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
    <ItemTemplate>
        <li><asp:LinkButton runat="server" ID="ViewCategory"
                Text='<%# String.Format("{0} ({1:N0})", _
                    Eval("CategoryName"), Eval("NumberOfProducts")) %>' />
        </li>
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategoriesAndNumberOfProducts" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

Выходные данные, отображаемые путем обновления DAL для включения NumberOfProducts столбца, совпадают с подходом ItemDataBound обработчика событий (вернитесь к рис. 4, чтобы увидеть снимок экрана repeater с именами категорий и количеством продуктов).

Шаг 3. Отображение продуктов выбранной категории

На этом этапе у нас есть Categories средство repeater, отображающее список категорий и количество продуктов в каждой категории. Repeater использует linkButton для каждой категории, которая при щелчке вызывает обратную передачу, после чего необходимо отобразить эти продукты для выбранной категории в CategoryProducts DataList.

Одна из проблем, стоящих перед нами, заключается в том, как отобразить в DataList только те продукты для выбранной категории. В учебнике Master/Detail Using a Selectable Master GridView with a DetailsView (Основные и подробные сведения) мы узнали, как создать элемент GridView, строки которого можно выбрать, при этом сведения о выбранной строке отображаются в DetailsView на той же странице. Объект ObjectDataSource GridView вернул сведения обо всех продуктах с помощью ProductsBLL метода s GetProducts() , а Объект ObjectDataSource detailsView — сведения о выбранном продукте GetProductsByProductID(productID) с помощью метода . Значение productID параметра было предоставлено декларативно путем его связывания со значением свойства GridView SelectedValue . К сожалению, repeater не имеет SelectedValue свойства и не может служить источником параметров.

Примечание

Это одна из тех проблем, которые возникают при использовании LinkButton в ретрансляторе. Если бы вместо этого мы использовали гиперссылку для передачи CategoryID через строку запроса, мы могли бы использовать это поле QueryString в качестве источника для значения параметра.

Но прежде чем беспокоиться об отсутствии SelectedValue свойства для Repeater, сначала привяжите DataList к ObjectDataSource и укажите его ItemTemplate.

В смарт-теге DataList добавьте новый объект ObjectDataSource с именем CategoryProductsDataSource и настройте его для использования ProductsBLL метода класса .GetProductsByCategoryID(categoryID) Так как dataList в этом руководстве предоставляет интерфейс только для чтения, вы можете задать для раскрывающихся списков на вкладках INSERT, UPDATE и DELETE значение (Нет).

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

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

GetProductsByCategoryID(categoryID) Так как метод ожидает входной параметр (categoryID), мастер настройки источника данных позволяет указать источник параметров. Если бы категории были указаны в GridView или DataList, для раскрывающегося списка Источник параметров необходимо задать значение Control, а в controlID — ID значение веб-элемента управления данными. Однако, поскольку в repeater нет SelectedValue свойства, его нельзя использовать в качестве источника параметров. Если вы проверка, вы увидите, что раскрывающийся список ControlID содержит только один элемент управления ID``CategoryProducts, ID элемент DataList.

Пока задайте для раскрывающегося списка Источник параметров значение Нет. В конечном итоге мы назначим значение этого параметра программным способом при щелчке категории LinkButton в repeater.

Не указывать источник параметра для параметра categoryID

Рис. 13. Не указывать источник параметра для categoryID параметра (щелкните для просмотра полноразмерного изображения)

После завершения работы мастера настройки источника данных Visual Studio автоматически создает список данных ItemTemplate. Замените это значение по умолчанию ItemTemplate шаблоном, который мы использовали в предыдущем руководстве, а также задайте для свойства DataList RepeatColumns значение 2. После внесения этих изменений декларативная разметка для DataList и связанного с ней объекта ObjectDataSource должна выглядеть следующим образом:

<asp:DataList ID="CategoryProducts" runat="server" DataKeyField="ProductID"
    DataSourceID="CategoryProductsDataSource" RepeatColumns="2"
    EnableViewState="False">
    <ItemTemplate>
        <h5><%# Eval("ProductName") %></h5>
        <p>
            Supplied by <%# Eval("SupplierName") %><br />
            <%# Eval("UnitPrice", "{0:C}") %>
        </p>
    </ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="CategoryProductsDataSource"
    OldValuesParameterFormatString="original_{0}"  runat="server"
    SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL">
    <SelectParameters>
        <asp:Parameter Name="categoryID" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

В настоящее CategoryProductsDataSource время параметр ObjectDataSource categoryID не задан, поэтому при просмотре страницы продукты не отображаются. Нам нужно задать значение этого параметра на CategoryID основе категории, щелкнутой в ретрансляторе. Это сопряжено с двумя проблемами: во-первых, как определить, когда был щелкнут LinkButton в repeater ItemTemplate , и, во-вторых, как определить CategoryID соответствующую категорию, для которой был нажат LinkButton?

Элементы управления LinkButton, такие как Button и ImageButton, Click имеют событие и Command событие . Событие Click предназначено для того, чтобы просто отметить, что элемент LinkButton был нажат. Однако иногда в дополнение к тому, что мы нажали LinkButton, необходимо также передать некоторые дополнительные сведения в обработчик событий. В этом случае свойствам LinkButton CommandName и CommandArgument можно назначить дополнительные сведения. Затем при щелчке linkButton срабатывает его Command событие (а не Click событие), а обработчику событий передаются значения CommandName свойств и CommandArgument .

Command При возникновении события из шаблона в repeater возникает событие Repeater ItemCommand и передается CommandName значения и CommandArgument для щелкнутого элемента LinkButton (или Button или ImageButton). Поэтому, чтобы определить, когда была нажата категория LinkButton в repeater, нам нужно сделать следующее:

  1. Присвойте свойству CommandName LinkButton в repeater s ItemTemplate некоторое значение (я использовал ListProducts ). Если задать это CommandName значение, событие LinkButton Command срабатывает при щелчке linkButton.
  2. Присвойте свойству LinkButton значение CommandArgument текущего элемента .CategoryID
  3. Создайте обработчик событий для события Repeater ItemCommand . В обработчике событий задайте CategoryProductsDataSource для параметра ObjectDataSource значение CategoryID переданного объекта CommandArgument.

ItemTemplate Следующая разметка для Categories Repeater реализует шаги 1 и 2. Обратите внимание, CommandArgument как значение присваивается элементам CategoryID данных с помощью синтаксиса привязки данных:

<ItemTemplate>
    <li>
        <asp:LinkButton CommandName="ListProducts"  runat="server"
            CommandArgument='<%# Eval("CategoryID") %>' ID="ViewCategory"
            Text='<%# string.Format("{0} ({1:N0})", _
                Eval("CategoryName"), Eval("NumberOfProducts")) %>'>
        </asp:LinkButton>
    </li>
</ItemTemplate>

При создании обработчика ItemCommand событий рекомендуется всегда сначала проверка входящее CommandName значение, так как любоеCommand событие, вызванное любым элементом Button, LinkButton или ImageButton в repeater, вызовет ItemCommand событие. Хотя в настоящее время у нас есть только один такой LinkButton, в будущем мы (или другой разработчик в нашей команде) можем добавить дополнительные веб-элементы управления кнопками в repeater, которые при щелчке вызывают тот же ItemCommand обработчик событий. Поэтому рекомендуется всегда проверка CommandName свойство и продолжать выполнение программной логики только в том случае, если оно соответствует ожидаемому значению.

Убедившись, что переданное CommandName значение равно ListProducts, обработчик событий назначает CategoryProductsDataSource параметр ObjectDataSource CategoryID значению переданного объекта CommandArgument. Это изменение objectDataSource SelectParameters автоматически приводит к повторной привязке DataList к источнику данных, отображая продукты для только что выбранной категории.

protected void Categories_ItemCommand(object source, RepeaterCommandEventArgs e)
{
    // If it's the "ListProducts" command that has been issued...
    if (string.Compare(e.CommandName, "ListProducts", true) == 0)
    {
        // Set the CategoryProductsDataSource ObjectDataSource's CategoryID parameter
        // to the CategoryID of the category that was just clicked (e.CommandArgument)...
        CategoryProductsDataSource.SelectParameters["CategoryID"].DefaultValue =
            e.CommandArgument.ToString();
    }
}

С помощью этих дополнений наше руководство завершено! Проверьте его в браузере. На рисунке 14 показан экран при первом посещении страницы. Так как категория еще не выбрана, продукты не отображаются. Если щелкнуть категорию, например "Произвести", эти продукты отображаются в категории "Продукт" в представлении с двумя столбцами (см. рис. 15).

Продукты не отображаются при первом посещении страницы

Рис. 14. При первом посещении страницы продукты не отображаются (щелкните для просмотра полноразмерного изображения)

Щелчок категории

Рис. 15. Щелчок категории "Производство" Списки соответствующего продукта справа (щелкните для просмотра полноразмерного изображения)

Сводка

Как мы видели в этом и предыдущем руководстве, master/подробные отчеты можно распределить по двум страницам или объединить на одной. Однако при отображении отчета master/сведений на одной странице возникают некоторые проблемы, связанные с размещением master и подробных записей на странице. В учебнике Master/Detail Using a Selectable Master GridView with a DetailsView (Основные и подробные сведения) было указано, что записи сведений отображаются над записями master. В этом руководстве мы использовали методы CSS, чтобы записи master перемещались слева от сведений.

Наряду с отображением master/подробных отчетов мы также имели возможность узнать, как получить количество продуктов, связанных с каждой категорией, а также как выполнять логику на стороне сервера при щелчке linkButton (или Button или ImageButton) в repeater.

В этом руководстве завершается изучение master/подробных отчетов с помощью DataList и Repeater. В следующем наборе учебников показано, как добавить возможности редактирования и удаления в элемент управления DataList.

Счастливое программирование!

Дополнительные материалы

Дополнительные сведения по темам, рассматриваемым в этом руководстве, см. в следующих ресурсах:

Об авторе

Скотт Митчелл (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.