Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este tutorial se amplía la relación maestro/detalle para agregar una tercera capa, usando dos controles DropDownList para seleccionar los registros padre y abuelo deseados.
Introducción
En el tutorial anterior hemos examinado cómo mostrar un informe de maestros y detalles sencillos mediante un único DropDownList rellenado con las categorías y una GridView que muestra los productos que pertenecen a la categoría seleccionada. Este patrón de informe funciona bien al mostrar registros que tienen una relación uno a varios y se puede ampliar fácilmente para trabajar en escenarios que incluyen varias relaciones de uno a varios. Por ejemplo, un sistema de entrada de pedidos tendría tablas que corresponden a clientes, pedidos y elementos de línea de pedidos. Un cliente determinado puede tener varios pedidos con cada pedido que consta de varios elementos. Estos datos se pueden presentar al usuario con dos DropDownLists y gridView. La primera lista desplegable tendría un elemento de lista para cada cliente de la base de datos, y los contenidos del segundo serán los pedidos realizados por el cliente seleccionado. GridView enumeraría los elementos de línea del orden seleccionado.
Aunque la base de datos Northwind incluye la información canónica de cliente, pedido y detalles del pedido en sus Customers
, Orders
, y Order Details
, estas tablas no se capturan en nuestra arquitectura. Sin embargo, todavía podemos ilustrar el uso de dos DropDownLists dependientes. El primer DropDownList enumerará las categorías y la segunda los productos que pertenecen a la categoría seleccionada. A continuación, un DetailsView enumerará los detalles del producto seleccionado.
Paso 1: Crear y rellenar las categorías DropDownList
Nuestro primer objetivo es agregar el DropDownList que enumera las categorías. Estos pasos se examinaron en detalle en el tutorial anterior, pero se resumen aquí para su integridad.
Abra la página MasterDetailsDetails.aspx
en la carpeta Filtering
, agregue un DropDownList a la página, establezca su propiedad ID
a Categories
y, a continuación, haga clic en Configurar origen de datos en su etiqueta inteligente. En el Asistente para configuración del origen de datos, elija agregar un nuevo origen de datos.
Figura 1: Agregar un nuevo origen de datos para dropDownList (haga clic para ver la imagen de tamaño completo)
El nuevo origen de datos debe ser, naturalmente, un ObjectDataSource. Asigne un nombre a este nuevo ObjectDataSource CategoriesDataSource
y haga que invoque el CategoriesBLL
método del GetCategories()
objeto.
Figura 2: Elegir usar la clase (CategoriesBLL
imagen de tamaño completo)
Figura 3: Configurar objectDataSource para usar el método (GetCategories()
imagen de tamaño completo)
Después de configurar ObjectDataSource, todavía es necesario especificar qué campo de origen de datos se debe mostrar en DropDownList Categories
y cuál debe configurarse como el valor del elemento de lista. Establezca el CategoryName
campo como pantalla y CategoryID
como valor para cada elemento de lista.
Figura 4: Hacer que dropDownList muestre el CategoryName
campo y use CategoryID
como valor (haga clic para ver la imagen de tamaño completo)
En este punto, tenemos un control DropDownList (Categories
) que se rellena con los registros de la Categories
tabla. Cuando el usuario elige una nueva categoría de la lista desplegable, queremos que se produzca un postback para actualizar la lista desplegable de productos que vamos a crear en el paso 2. Por lo tanto, active la opción Habilitar AutoPostBack desde la etiqueta inteligente de DropDownList categories
.
Figura 5: Habilitar AutoPostBack para la lista desplegable (Categories
imagen en tamaño completo)
Paso 2: Mostrar los productos de la categoría seleccionada en una segunda lista desplegable
Con la lista desplegable Categories
completada, nuestro siguiente paso es mostrar una lista desplegable de productos pertenecientes a la categoría seleccionada. Para ello, agregue otro DropDownList a la página denominada ProductsByCategory
. Al igual que con Categories
DropDownList, cree un ObjectDataSource nuevo para ProductsByCategory
DropDownList denominado ProductsByCategoryDataSource
.
Figura 6: Agregar un nuevo origen de datos para dropDownList (ProductsByCategory
imagen de tamaño completo)
Figura 7: Crear un nuevo objetoDataSource denominado ProductsByCategoryDataSource
(haga clic para ver la imagen de tamaño completo)
Puesto que DropDownList ProductsByCategory
debe mostrar solo los productos que pertenecen a la categoría seleccionada, haga que ObjectDataSource invoque el GetProductsByCategoryID(categoryID)
método desde el ProductsBLL
objeto .
Figura 8: Elegir usar la clase (ProductsBLL
imagen de tamaño completo)
Figura 9: Configurar objectDataSource para usar el método (GetProductsByCategoryID(categoryID)
imagen de tamaño completo)
En el paso final del asistente necesitamos especificar el valor del parámetro categoryID
. Asigne este parámetro al elemento seleccionado de Categories
DropDownList.
Figura 10: Extraer el valor del categoryID
parámetro de la lista desplegable Categories
(haga clic para ver la imagen de tamaño completo)
Con objectDataSource configurado, todo lo que queda es especificar qué campos de origen de datos se usan para la presentación y el valor de los elementos de DropDownList. Muestra el ProductName
campo y usa el ProductID
campo como valor.
Figura 11: Especifique los campos de origen de datos utilizados para las propiedades ListItem
y Text
de Value
del DropDownList (haga clic para ver la imagen de tamaño completo)
Con ObjectDataSource y ProductsByCategory
DropDownList configurados en nuestra página se mostrarán dos DropDownLists: la primera enumerará todas las categorías, mientras que la segunda enumerará los productos que pertenecen a la categoría seleccionada. Cuando el usuario selecciona una nueva categoría en la primera lista desplegable, se producirá un postback y la segunda lista desplegable será reabierta, mostrando los productos que pertenecen a la categoría recién seleccionada. Las figuras 12 y 13 muestran MasterDetailsDetails.aspx
en acción cuando se ven a través de un navegador.
Figura 12: Cuando se visita por primera vez la página, la categoría bebidas está seleccionada (haga clic para ver la imagen de tamaño completo)
Figura 13: Elegir una categoría diferente Muestra los productos de la nueva categoría (haga clic para ver la imagen de tamaño completo)
Actualmente, DropDownList productsByCategory
, cuando se cambia, no provoca un postback. Sin embargo, queremos que se produzca un postback una vez que agreguemos un DetailsView para mostrar los detalles del producto seleccionado (paso 3). Por lo tanto, active la casilla "Habilitar AutoPostBack" de la etiqueta inteligente de DropDownList productsByCategory
.
Figura 14: Habilitar la característica AutoPostBack para dropDownList productsByCategory
(haga clic para ver la imagen de tamaño completo)
Paso 3: Usar una vista de detalles para mostrar los detalles del producto seleccionado
El último paso consiste en mostrar los detalles del producto seleccionado en detailsView. Para ello, agregue un componente DetailsView a la página, establezca su propiedad ID
a ProductDetails
, y cree un ObjectDataSource para ella. Configure este ObjectDataSource para extraer sus datos del método ProductsBLL
de la clase GetProductByProductID(productID)
utilizando el valor seleccionado del DropDownList ProductsByCategory
para el valor del parámetro productID
.
Figura 15: Elegir usar la clase (ProductsBLL
la imagen de tamaño completo)
Figura 16: Configurar objectDataSource para usar el método (GetProductByProductID(productID)
la imagen de tamaño completo)
Figura 17: Extraer el valor del parámetro de la productID
(ProductsByCategory
)
Puede elegir mostrar cualquiera de los campos disponibles en DetailsView. He optado por quitar los ProductID
, SupplierID
, y CategoryID
campos y he reordenado y formateado los campos restantes. Además, he borrado las propiedades de Height
y Width
de DetailsView, lo que permite que DetailsView se expanda al ancho necesario para mostrar mejor sus datos en lugar de restringirse a un tamaño especificado. El marcado completo aparece a continuación:
<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>
Dedique un momento a probar la MasterDetailsDetails.aspx
página en un explorador. A primera vista puede parecer que todo funciona según lo deseado, pero hay un problema sutil. Al elegir una nueva categoría, DropDownList ProductsByCategory
se actualiza para incluir esos productos para la categoría seleccionada, pero DetailsView ProductDetails
continuó mostrando la información del producto anterior. DetailsView se actualiza al elegir un producto diferente para la categoría seleccionada. Además, si realiza pruebas lo suficientemente exhaustivas, verá que si elige continuamente nuevas categorías (como elegir Bebidas en DropDownList Categories
, luego Condimentos, después Confitería) cada otra selección de categorías hace que DetailsView ProductDetails
se actualice.
Para ayudar a concretar este problema, echemos un vistazo a un ejemplo específico. Cuando visitas la página por primera vez, la categoría Bebidas está seleccionada y los productos relacionados se cargan en el DropDownList ProductsByCategory
. Chai es el producto seleccionado y sus detalles se muestran en detailsView, como se muestra en la ProductDetails
figura 18.
Figura 18: Los detalles del producto seleccionado se muestran en una Vista de detalles (haga clic para ver la imagen de tamaño completo)
Si cambias la selección de categoría de Bebidas a Condimentos, se produce un postback y la lista desplegable ProductsByCategory
se actualiza en consecuencia, pero la vista de detalles todavía muestra los detalles de Chai.
Figura 19: Los detalles del producto seleccionado previamente se siguen mostrando (haga clic para ver la imagen de tamaño completo)
La selección de un nuevo producto de la lista actualiza DetailsView según lo previsto. Si elige una nueva categoría después de cambiar el producto, DetailsView de nuevo no se actualizará. Sin embargo, si en lugar de elegir un nuevo producto seleccionas una nueva categoría, DetailsView se actualizaría. ¿Qué demonios está pasando aquí?
El problema es un problema de tiempo en el ciclo de vida de la página. Cada vez que se solicita una página, pasa por varios pasos como parte de su renderizado. En uno de estos pasos, los controles ObjectDataSource comprueban si alguno de sus SelectParameters
valores ha cambiado. Si es así, el control web de datos enlazado a ObjectDataSource sabe que necesita actualizar su presentación. Por ejemplo, cuando se selecciona una nueva categoría, ProductsByCategoryDataSource
ObjectDataSource detecta que sus valores de parámetro han cambiado y que DropDownList ProductsByCategory
se vuelve a enlazar, obteniendo los productos de la categoría seleccionada.
El problema que surge en esta situación es que el punto del ciclo de vida de la página en el que los ObjectDataSources comprueban los parámetros modificados se produce antes de reencadenar los controles Web de datos asociados. Por lo tanto, al seleccionar una nueva categoría, ProductsByCategoryDataSource
ObjectDataSource detecta un cambio en el valor de su parámetro. El ObjectDataSource usado por el ProductDetails
DetailsView, sin embargo, no observa ningún cambio de este tipo porque el ProductsByCategory
DropDownList aún no se ha reasignado. Más adelante en el ciclo de vida, DropDownList ProductsByCategory
se vuelve a enlazar a su ObjectDataSource, capturando los productos de la categoría recién seleccionada. Aunque el ProductsByCategory
valor de DropDownList ha cambiado, el ProductDetails
ObjectDataSource de DetailsView ya ha realizado su comprobación de valor de parámetro; por lo tanto, DetailsView muestra sus resultados anteriores. Esta interacción se muestra en la figura 20.
Figura 20: El valor DropDownList cambia después de que el ProductsByCategory
ProductDetails
objeto ObjectDataSource de DetailsView comprueba los cambios (haga clic para ver la imagen de tamaño completo)
Para solucionar esto, es necesario volver a enlazar explícitamente el ProductDetails
DetailsView después de que se haya enlazado el ProductsByCategory
DropDownList. Para lograr esto, llamamos al método del ProductDetails
DetailsView DataBind()
cuando se dispara el evento del ProductsByCategory
DropDownList DataBound
. Agregue el siguiente código de controlador de eventos a la clase de código subyacente de la MasterDetailsDetails.aspx
página (consulte "Establecer mediante programación los valores de parámetro de ObjectDataSource" para obtener una explicación sobre cómo agregar un controlador de eventos):
protected void ProductsByCategory_DataBound(object sender, EventArgs e)
{
ProductDetails.DataBind();
}
Una vez agregada esta llamada explícita al ProductDetails
método DetailsView DataBind()
, el tutorial funciona según lo previsto. En la figura 21 se resalta cómo este cambio ha corregido nuestro problema anterior.
Figura 21: El DetailsView ProductDetails
se actualiza explícitamente cuando se dispara el evento del DropDownList ProductsByCategory
(DataBound
)
Resumen
DropDownList actúa como un elemento de interfaz de usuario ideal para informes maestros y detallados en los que hay una relación uno a varios entre los registros maestro y de detalles. En el tutorial anterior vimos cómo usar una lista desplegable única para filtrar los productos mostrados por la categoría seleccionada. En este tutorial, reemplazamos gridView de productos por dropDownList y usamos un DetailsView para mostrar los detalles del producto seleccionado. Los conceptos descritos en este tutorial se pueden extender fácilmente a los modelos de datos que implican varias relaciones de uno a varios, como clientes, pedidos y elementos de pedido. En general, siempre puedes agregar una lista desplegable para cada una de las entidades "una" en las relaciones de uno a muchos.
¡Feliz programación!
Acerca del autor
Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha estado trabajando con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 2.0 en 24 horas. Se puede contactar con él en mitchell@4GuysFromRolla.com.
Agradecimientos especiales a
Esta serie de tutoriales contó con la revisión de muchos revisores que fueron de gran ayuda. El revisor principal de este tutorial fue Hilton Giesenow. ¿Le interesa revisar mis próximos artículos de MSDN? Si es así, mándame un mensaje a mitchell@4GuysFromRolla.com.