Usar CascadingDropDown con una base de datos (C#)

por Christian Wenz

Descargar PDF

El control CascadingDropDown del Kit de herramientas de control de AJAX extiende un control DropDownList para que los cambios en uno de estos controles carguen los valores asociados en otro de estos controles. Para que esto funcione, se debe crear un servicio web especial.

Información general

El control CascadingDropDown del Kit de herramientas de control de AJAX extiende un control DropDownList para que los cambios en uno de estos controles carguen los valores asociados en otro de estos controles. (Por ejemplo, una lista proporciona una lista de estados de EE. UU., y la siguiente lista se rellena con las principales ciudades de ese estado). Para que esto funcione, se debe crear un servicio web especial.

Pasos

En primer lugar, se requiere un origen de datos. En este ejemplo se usa la base de datos AdventureWorks y Microsoft SQL Server 2005 Express Edition. La base de datos es una parte opcional de una instalación de Visual Studio (incluido Express Edition) y también está disponible como una descarga independiente en https://go.microsoft.com/fwlink/?LinkId=64064. La base de datos AdventureWorks forma parte de los ejemplos y las bases de datos de ejemplo de SQL Server 2005 (puede descargarla en https://www.microsoft.com/download/details.aspx?id=10679). La manera más fácil de configurar la base de datos es usar Microsoft SQL Server Management Studio (/sql/ssms/download-sql-server-management-studio-ssms) y adjuntar el archivo de base de datos AdventureWorks.mdf.

En este ejemplo, se supone que la instancia de SQL Server 2005 Express Edition se llama SQLEXPRESS y reside en la misma máquina que el servidor web; esta es también la configuración predeterminada. Si la configuración es diferente, tiene que adaptar la información de conexión de la base de datos.

Para activar la funcionalidad de ASP.NET AJAX y el Kit de herramientas de control, el control ScriptManager debe colocarse en cualquier parte de la página (pero dentro del elemento <form>):

<asp:ScriptManager ID="asm" runat="server" />

En el paso siguiente, se requieren dos controles DropDownList. En este ejemplo, usamos la información del proveedor y de contacto de AdventureWorks, por lo que creamos una lista para los proveedores disponibles y otra para los contactos disponibles:

<div>
 Vendor: <asp:DropDownList ID="VendorsList" runat="server"/><br />
 Contacts: <asp:DropDownList ID="ContactsList" runat="server"/><br />
</div>

A continuación, se deben agregar dos controles extensores CascadingDropDown a la página. Una rellena la primera lista (proveedores) y la otra rellena la segunda lista (contactos). Se deben establecer los atributos siguientes:

  • ServicePath: dirección URL de un servicio web que proporciona las entradas de la lista.
  • ServiceMethod: método web que proporciona las entradas de la lista.
  • TargetControlID: identificador de lista desplegable.
  • Category: información de categoría que se envía al método web cuando se le llama.
  • PromptText: texto que se muestra al cargar datos de lista de forma asincrónica desde el servidor.
  • ParentControlID: (opcional) lista desplegable primaria que desencadena la carga de la lista actual.

Según el lenguaje de programación usado, el nombre del servicio web en cuestión cambia, pero todos los demás valores de atributo permanecen. Este es el elemento CascadingDropDown de la primera lista desplegable:

<ajaxToolkit:CascadingDropDown ID="ccd1" runat="server"
 ServicePath="CascadingDropdown1.cs.asmx" ServiceMethod="GetVendors"
 TargetControlID="VendorsList" Category="Vendor"
 PromptText="Select Vendor" />

Los controles extensores de la segunda lista deben establecer el atributo ParentControlID para que la selección de una entrada en la lista de proveedores desencadene la carga de los elementos asociados en la lista de contactos.

<ajaxToolkit:CascadingDropDown ID="ccd2" runat="server"
 ServicePath="CascadingDropdown1.cs.asmx" ServiceMethod="GetContactsForVendor"
 TargetControlID="ContactsList" ParentControlID="VendorsList"
 Category="Contact"
 PromptText="Select Contact" />

El trabajo real se realiza entonces en el servicio web, que se configura de la manera siguiente. Observe que se usa el atributo [ScriptService]; de lo contrario, ASP.NET AJAX no puede crear el proxy de JavaScript para acceder a los métodos web desde el código de script del lado cliente.

<%@ WebService Language="C#" Class="CascadingDropdown1" %>
using System.Web.Script.Services;
using AjaxControlToolkit;
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data.SqlClient;
[ScriptService]
public class CascadingDropdown1 : System.Web.Services.WebService
{
 // ...
}

La firma de los métodos web a los que llama CascadingDropDown es la siguiente:

public CascadingDropDownNameValue[] MethodNameHere(string knownCategoryValues, 
    string category)

Por lo tanto, el valor devuelto debe ser una matriz de tipo CascadingDropDownNameValue definida por el Kit de herramientas de control. El método GetVendors() es bastante fácil de implementar: el código se conecta a la base de datos AdventureWorks y consulta los primeros 25 proveedores. El primer parámetro del constructor CascadingDropDownNameValue es el título de la entrada de lista, el segundo su valor (atributo value en el elemento HTML option<>). Este es el código:

[WebMethod]
public CascadingDropDownNameValue[] GetVendors(string knownCategoryValues, string category)
{
    SqlConnection conn = new SqlConnection("server=(local)\\SQLEXPRESS; 
    Integrated Security=true; Initial Catalog=AdventureWorks");
    conn.Open();
    SqlCommand comm = new SqlCommand("SELECT TOP 25 VendorID, Name 
    FROM Purchasing.Vendor",conn);
    SqlDataReader dr = comm.ExecuteReader();
    List<CascadingDropDownNameValue> l = new List<CascadingDropDownNameValue>();
    while (dr.Read())
    {
        l.Add(new CascadingDropDownNameValue(dr["Name"].ToString(),
        dr["VendorID"].ToString()));
    }
    conn.Close();
    return l.ToArray();
}

Obtener los contactos asociados de un proveedor (nombre de método GetContactsForVendor()) es un poco más complicado. En primer lugar, se debe determinar el proveedor que se ha seleccionado en la primera lista desplegable. El Kit de herramientas de control define un método auxiliar para esa tarea: el método ParseKnownCategoryValuesString() devuelve un elemento StringDictionary con los datos desplegables:

[WebMethod]
public CascadingDropDownNameValue[] GetContactsForVendor(string knownCategoryValues, 
    string category)
{
    int VendorID;
    CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);

Por motivos de seguridad, estos datos deben validarse primero. Por lo tanto, si hay una entrada Vendor (porque la propiedad Category del primer elemento CascadingDropDown está establecida en "Vendor"), se puede recuperar el identificador del proveedor seleccionado:

if (!kv.ContainsKey("Vendor") || !Int32.TryParse(kv["Vendor"],out VendorID)) 
{
    throw new ArgumentException("Couldn't find vendor.");
};

Por tanto, el resto del método es bastante sencillo. El identificador del proveedor se usa como parámetro para una consulta SQL que recupera todos los contactos asociados a ese proveedor. Una vez más, el método devuelve una matriz de tipo CascadingDropDownNameValue.

SqlConnection conn = new SqlConnection("server=(local)\\SQLEXPRESS; 
 Integrated Security=true; Initial Catalog=AdventureWorks");
 conn.Open();
 SqlCommand comm = new SqlCommand("SELECT Person.Contact.ContactID, FirstName, LastName 
 FROM Person.Contact,Purchasing.VendorContact 
 WHERE VendorID=@VendorID 
 AND Person.Contact.ContactID=Purchasing.VendorContact.ContactID",conn);
 comm.Parameters.AddWithValue("@VendorID", VendorID);
 SqlDataReader dr = comm.ExecuteReader();
 List<CascadingDropDownNameValue> l = new List<CascadingDropDownNameValue>();
 while (dr.Read())
 {
 l.Add(new CascadingDropDownNameValue(
 dr["FirstName"].ToString() + " " + dr["LastName"].ToString(),
 dr["ContactID"].ToString()));
 }
 conn.Close();
 return l.ToArray();
}

Cargue la página ASP.NET y, después de un corto tiempo, la lista de proveedores se rellena con 25 entradas. Elija una entrada y observe cómo la segunda lista desplegable se rellena con datos.

The first list is filled automatically

La primera lista se rellena automáticamente (haga clic para ver la imagen a tamaño completo).

The second list is filled according to the selection in the first list

La segunda lista se rellena según la selección de la primera lista (haga clic para ver la imagen a tamaño completo).