Compartir a través de


Filtrado principal/detalle con dos listas desplegables (C#)

de Scott Mitchell

Descargar PDF

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.

Agregar un nuevo origen de datos para DropDownList

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.

Elegir usar la clase CategoriesBLL

Figura 2: Elegir usar la clase (CategoriesBLL imagen de tamaño completo)

Configurar ObjectDataSource para usar el método GetCategories()

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.

Haga que DropDownList muestre el campo CategoryName y Use CategoryID como valor

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.

Habilitar AutoPostBack para las categorías DropDownList

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.

Agregar un nuevo origen de datos para productsByCategory DropDownList

Figura 6: Agregar un nuevo origen de datos para dropDownList (ProductsByCategory imagen de tamaño completo)

Crear un nuevo objeto DataSource denominado ProductsByCategoryDataSource

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 .

Captura de pantalla de la ventana Configurar origen de datos: productsByCategoryDataSource con ProductsBLL seleccionado y el botón Siguiente resaltado.

Figura 8: Elegir usar la clase (ProductsBLL imagen de tamaño completo)

Configurar ObjectDataSource para usar el método GetProductsByCategoryID(categoryID)

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.

Extraer el valor del parámetro categoryID de la lista desplegable Categorías

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.

Especificar los campos de origen de datos utilizados para las propiedades de Texto y Valor de los ListItems en el DropDownList

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.

Cuando se visita por primera vez la página, se selecciona la categoría bebidas.

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)

Elegir una categoría diferente muestra los productos de la nueva categoría

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.

Habilitar la característica AutoPostBack para los productosByCategory DropDownList

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.

Captura de pantalla de la ventana Configurar origen de datos : productsByCategoryDataSource, donde ProductsBLL está seleccionado y el botón Siguiente está resaltado.

Figura 15: Elegir usar la clase (ProductsBLL la imagen de tamaño completo)

Configurar ObjectDataSource para usar el método GetProductByProductID(productID)

Figura 16: Configurar objectDataSource para usar el método (GetProductByProductID(productID) la imagen de tamaño completo)

Obtener el valor del parámetro productID de la lista desplegable ProductsByCategory

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.

Los detalles del producto seleccionado se muestran en un DetailsView

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.

Todavía se muestran los detalles del producto seleccionado anteriormente

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.

El valor ProductsByCategory DropDownList cambia después de que el objeto ObjectDataSource de ProductDetailsView compruebe si hay cambios

Figura 20: El valor DropDownList cambia después de que el ProductsByCategoryProductDetails 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.

ProductDetails DetailsView se actualiza explícitamente cuando se desencadena el evento DataBound de ProductsByCategory DropDownList

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.