Фильтрация "Основной/подробности" с помощью двух элементов управления DropDownList (VB)
В этом руководстве расширена связь master/подробностей, чтобы добавить третий уровень, используя два элемента управления DropDownList для выбора нужных записей родителей и бабушек и дедушек.
Введение
В предыдущем руководстве мы рассмотрели, как отобразить простой отчет master/details с помощью одного раскрывающегося списка, заполненного категориями и GridView, в котором отображаются продукты, относящиеся к выбранной категории. Этот шаблон отчета хорошо работает при отображении записей, которые имеют отношение "один ко многим" и могут быть легко расширены для работы в сценариях с несколькими связями "один ко многим". Например, система ввода заказов будет содержать таблицы, соответствующие клиентам, заказам и позициям строк заказов. У конкретного клиента может быть несколько заказов, каждый из которых состоит из нескольких позиций. Такие данные могут быть представлены пользователю с помощью двух DropDownLists и GridView. Первый DropDownList будет иметь элемент списка для каждого клиента в базе данных, а второй — это заказы, размещенные выбранным клиентом. GridView выводит список строк из выбранного порядка.
Хотя база данных Northwind содержит канонические сведения о клиентах, заказах и заказах в таблицах Customers
, Orders
и Order Details
, эти таблицы не фиксируются в нашей архитектуре. Тем не менее, мы по-прежнему можем проиллюстрировать использование двух зависимых DropDownLists. В первом списке DropDownList будут перечислены категории, а во втором — продукты, относящиеся к выбранной категории. После этого в Представлении сведений отобразится список сведений о выбранном продукте.
Шаг 1. Создание и заполнение раскрывающегося списка категорий
Наша первая цель — добавить Раскрывающийся список, в который перечислены категории. Эти шаги были подробно рассмотрены в предыдущем руководстве, но приведены здесь для полноты.
Откройте страницу MasterDetailsDetails.aspx
в папке Filtering
, добавьте на нее раскрывающийся список, задайте для ее ID
свойства Categories
значение , а затем щелкните ссылку Настройка источника данных в смарт-теге. В мастере настройки источника данных выберите добавление нового источника данных.
Рис. 1. Добавление нового источника данных для Раскрывающегося списка (щелкните для просмотра полноразмерного изображения)
Новый источник данных, естественно, должен быть ObjectDataSource. Присвойте этому новому объекту имя ObjectDataSource CategoriesDataSource
и вызовите CategoriesBLL
метод объекта GetCategories()
.
Рис. 2. Выбор использования CategoriesBLL
класса (щелкните для просмотра полноразмерного изображения)
Рис. 3. Настройка ObjectDataSource для использования GetCategories()
метода (щелкните для просмотра полноразмерного изображения)
После настройки ObjectDataSource по-прежнему необходимо указать, какое поле источника данных должно отображаться в Categories
Раскрывающемся списке, а какое — в качестве значения для элемента списка. CategoryName
Задайте поле в качестве отображения и CategoryID
значения для каждого элемента списка.
Рис. 4. Отображение поля в раскрывающемся CategoryName
списке и использование CategoryID
в качестве значения (щелкните для просмотра полноразмерного изображения)
На этом этапе у нас есть элемент управления DropDownList (Categories
), заполненный записями из Categories
таблицы. Когда пользователь выбирает новую категорию в Раскрывающемся списке, нам потребуется выполнить обратную передачу, чтобы обновить раскрывающийся список продукта, который мы создадим на шаге 2. Поэтому проверка параметр Включить AutoPostBack из categories
смарт-тега DropDownList.
Рис. 5. Включение AutoPostBack для Categories
Раскрывающегося списка (щелкните для просмотра полноразмерного изображения)
Шаг 2. Отображение продуктов выбранной категории во втором раскрывающемся списке
Categories
После завершения dropDownList наш следующий шаг заключается в отображении раскрывающегося списка продуктов, относящихся к выбранной категории. Для этого добавьте еще один Раскрывающийся список на страницу с именем ProductsByCategory
. Как и в случае Categories
с DropDownList, создайте объект ObjectDataSource для ProductsByCategory
DropDownList с именем ProductsByCategoryDataSource
.
Рис. 6. Добавление нового источника данных для раскрывающегося ProductsByCategory
списка (щелкните для просмотра полноразмерного изображения)
Рис. 7. Создание объекта ObjectDataSource с именем ProductsByCategoryDataSource
(щелкните для просмотра полноразмерного изображения)
Так как dropDownList ProductsByCategory
должен отображать только те продукты, которые относятся к выбранной категории, объект ObjectDataSource вызывает GetProductsByCategoryID(categoryID)
метод из ProductsBLL
объекта .
Рис. 8. Выбор использования ProductsBLL
класса (щелкните для просмотра полноразмерного изображения)
Рис. 9. Настройка ObjectDataSource для использования GetProductsByCategoryID(categoryID)
метода (щелкните для просмотра полноразмерного изображения)
На последнем шаге мастера необходимо указать значение categoryID
параметра . Назначьте этот параметр выбранному элементу из Раскрывающегося Categories
списка.
Рис. 10. Извлечение categoryID
значения параметра из Categories
раскрывающегося списка (щелкните для просмотра полноразмерного изображения)
После настройки ObjectDataSource остается только указать, какие поля источника данных используются для отображения и значения элементов DropDownList. ProductName
Отображение поля и использование поля в ProductID
качестве значения.
Рис. 11. Указание полей источника данных, используемых для свойств и Value
свойств раскрывающегося списка Text
ListItem
(щелкните для просмотра полноразмерного изображения)
При настройке ObjectDataSource и ProductsByCategory
DropDownList на нашей странице будут отображаться два списка DropDownList: первый будет выводить список всех категорий, а второй — эти продукты, принадлежащие выбранной категории. Когда пользователь выбирает новую категорию из первого DropDownList, происходит обратная связь, а второй DropDownList будет восстановлен, отображая продукты, которые относятся к только что выбранной категории. Рисунки 12 и 13 показаны MasterDetailsDetails.aspx
в действии при просмотре в браузере.
Рис. 12. При первом посещении страницы выбрана категория "Напитки" (щелкните для просмотра полноразмерного изображения)
Рис. 13. Выбор другой категории Отображает продукты новой категории (щелкните для просмотра полноразмерного изображения)
В настоящее productsByCategory
время dropDownList при изменении не вызывает обратной передачи. Однако мы хотим, чтобы обратная связь произошла после добавления DetailsView для отображения сведений о выбранном продукте (шаг 3). Поэтому проверка флажок Включить AutoPostBack из productsByCategory
смарт-тега DropDownList.
Рис. 14. Включение функции AutoPostBack для productsByCategory
раскрывающегося списка (щелкните для просмотра полноразмерного изображения)
Шаг 3. Использование DetailsView для отображения сведений о выбранном продукте
Последним шагом является отображение сведений о выбранном продукте в DetailsView. Для этого добавьте DetailsView на страницу, задайте для его ID
свойства ProductDetails
значение и создайте для него объект ObjectDataSource. Настройте этот объект ObjectDataSource для извлечения данных из ProductsBLL
метода класса GetProductByProductID(productID)
, используя выбранное ProductsByCategory
значение DropDownList для значения productID
параметра .
Рис. 15. Выбор использования ProductsBLL
класса (щелкните для просмотра полноразмерного изображения)
Рис. 16. Настройка ObjectDataSource для использования GetProductByProductID(productID)
метода (щелкните для просмотра полноразмерного изображения)
Рис. 17. Извлечение productID
значения параметра из ProductsByCategory
раскрывающегося списка (щелкните для просмотра полноразмерного изображения)
Вы можете выбрать отображение любого из доступных полей в Представлении сведений ProductDetails
. Я решил удалить ProductID
поля , SupplierID
и CategoryID
, а остальные поля переупорядочены и отформатированы. Кроме того, я очистил свойства DetailsView Height
и Width
, что позволило DetailsView расширить до ширины, необходимой для лучшего отображения данных, а не ограничивать их заданным размером. Полная разметка отображается ниже:
<asp:DetailsView ID="ProductDetails" runat="server"
AutoGenerateRows="False" DataKeyNames="ProductID"
DataSourceID="ObjectDataSource1" EnableViewState="False">
<Fields>
<asp:BoundField DataField="ProductName"
HeaderText="Product" SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName"
HeaderText="Category" ReadOnly="True"
SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName"
HeaderText="Supplier" ReadOnly="True"
SortExpression="SupplierName" />
<asp:BoundField DataField="QuantityPerUnit"
HeaderText="Qty/Unit" SortExpression="QuantityPerUnit" />
<asp:BoundField DataField="UnitPrice"
DataFormatString="{0:c}" HeaderText="Price"
HtmlEncode="False" SortExpression="UnitPrice" />
<asp:BoundField DataField="UnitsInStock"
HeaderText="UnitsInStock"
SortExpression="Units In Stock" />
<asp:BoundField DataField="UnitsOnOrder"
HeaderText="UnitsOnOrder"
SortExpression="Units On Order" />
<asp:BoundField DataField="ReorderLevel"
HeaderText="ReorderLevel" SortExpression="Reorder Level" />
<asp:CheckBoxField DataField="Discontinued"
HeaderText="Discontinued" SortExpression="Discontinued" />
</Fields>
</asp:DetailsView>
Уделите немного времени, чтобы опробовать страницу MasterDetailsDetails.aspx
в браузере. На первый взгляд может показаться, что все работает, как нужно, но есть тонкие проблемы. При выборе новой категории ProductsByCategory
список DropDownList обновляется, чтобы включить эти продукты для выбранной категории, но ProductDetails
в DetailsView по-прежнему отображаются предыдущие сведения о продукте. DetailsView обновляется при выборе другого продукта для выбранной категории. Кроме того, при достаточно тщательном тестировании вы обнаружите, что при постоянном выборе новых категорий (например, при выборе напитков в Categories
Раскрывающемся списке, затем приправы, затем кондитерских изделий) все остальные категории ProductDetails
приведут к обновлению DetailsView.
Чтобы упростить конкретизацию этой проблемы, рассмотрим конкретный пример. При первом посещении страницы выбирается категория «Напитки», а связанные продукты загружаются в ProductsByCategory
Раскрывающийся список. Chai является выбранным продуктом, и его сведения отображаются в ProductDetails
DetailsView, как показано на рисунке 18.
Рис. 18. Сведения о выбранном продукте отображаются в Представлении сведений (щелкните для просмотра полноразмерного изображения)
Если выбрать категорию с "Напитки" на "Приправы", происходит обратная связь и ProductsByCategory
dropDownList обновляется соответствующим образом, но DetailsView по-прежнему отображает сведения о Chai.
Рис. 19. Сведения о ранее выбранном продукте по-прежнему отображаются (щелкните для просмотра полноразмерного изображения)
При выборе нового продукта из списка представление DetailsView обновляется должным образом. Если вы выберете новую категорию после изменения продукта, detailsView снова не будет обновляться. Однако если вместо выбора нового продукта вы выбрали новую категорию, представление DetailsView обновится. Что в мире происходит здесь?
Проблема связана со временем в жизненном цикле страницы. При каждом запросе страницы она выполняет ряд шагов в качестве отрисовки. На одном из этих шагов элементы управления ObjectDataSource проверка, чтобы узнать, изменилось ли какое-либо из их SelectParameters
значений. Если это так, веб-элемент управления данными, привязанный к ObjectDataSource, знает, что ему необходимо обновить отображение. Например, при выборе новой категории ObjectDataSource обнаруживает, ProductsByCategoryDataSource
что ее значения параметров изменились, и ProductsByCategory
DropDownList повторно привязывает себя, получая продукты для выбранной категории.
Проблема, возникающая в этой ситуации, заключается в том, что точка жизненного цикла страницы, в которую ObjectDataSources проверка для измененных параметров, происходит до повторной привязки связанных веб-элементов управления данными. Таким образом, при выборе новой категории ProductsByCategoryDataSource
ObjectDataSource обнаруживает изменение значения своего параметра. Объект ObjectDataSource, используемый ProductDetails
DetailsView, не замечает таких изменений, так как ProductsByCategory
DropDownList еще не был восстановлен. Позже в жизненном цикле ProductsByCategory
DropDownList повторно привязывался к объекту ObjectDataSource, захватывая продукты для только что выбранной категории. ProductsByCategory
Хотя значение DropDownList изменилось, ProductDetails
объект ObjectDataSource DetailsView уже выполнил проверка значение параметра, поэтому DetailsView отображает предыдущие результаты. Это взаимодействие показано на рис. 20.
Рис. 20. Значение ProductsByCategory
Раскрывающегося списка изменяется после ProductDetails
того, как ObjectDataSource Объекта DetailsView проверяет наличие изменений (щелкните, чтобы просмотреть полноразмерное изображение)
Чтобы устранить эту проблему, необходимо явно повторно привязать ProductDetails
DetailsView после привязки ProductsByCategory
DropDownList. Это можно сделать, вызвав ProductDetails
метод DetailsView DataBind()
при ProductsByCategory
возникновении события DropDownList DataBound
. Добавьте следующий код обработчика событий в MasterDetailsDetails.aspx
класс кода программной части страницы (сведения о добавлении обработчика событий см. в разделе "Программное задание значений параметров ObjectDataSource").
Protected Sub ProductsByCategory_DataBound(sender As Object, e As EventArgs) _
Handles ProductsByCategory.DataBound
ProductDetails.DataBind()
End Sub
После добавления этого явного ProductDetails
вызова метода DetailsView DataBind()
учебник работает должным образом. На рисунке 21 показано, как это изменение устранило проблему, возникшую ранее.
Рис. 21. DetailsView ProductDetails
явно обновляется при ProductsByCategory
возникновении события DropDownList DataBound
(щелкните, чтобы просмотреть полноразмерное изображение)
Сводка
DropDownList служит идеальным элементом пользовательского интерфейса для master/подробных отчетов, в которых между master и подробными записями существует связь "один ко многим". В предыдущем руководстве мы узнали, как использовать один dropDownList для фильтрации продуктов, отображаемых по выбранной категории. В этом руководстве мы заменили GridView продуктов dropDownList и использовали DetailsView для отображения сведений о выбранном продукте. Основные понятия, описанные в этом руководстве, можно легко распространить на модели данных, включающие несколько связей "один ко многим", таких как клиенты, заказы и элементы заказов. Как правило, вы всегда можете добавить DropDownList для каждой из "одной" сущностей в отношениях "один ко многим".
Счастливое программирование!
Об авторе
Скотт Митчелл (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 как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по