miércoles, 24 de marzo de 2010

C# - [ASP.NET] DropDownList anidados

 

Introducción


El objetivo de este articulo será el de demostrar con un ejemplo completo como cargar controles que dependen de la información de toros controles para desplegar la información.

Se usara para este ejemplo tres controles DropDownList que irán filtrando en cascada, hasta llegar al una grilla final, implementada con el GridView, la cual mostrara los clientes que realizaron la compra.

 

Cascada de Eventos


El punto importante en el ejemplo es analizar como los eventos de los controles interactúan entre ellos.

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                LoadComboArtist();
            }
        }

        protected void ddlArtist_SelectedIndexChanged(object sender, EventArgs e)
        {
            int ArtistId = Convert.ToInt32(ddlArtist.SelectedValue);

            LoadComboAlbum(ArtistId);
            
        }

        protected void ddlAlbum_SelectedIndexChanged(object sender, EventArgs e)
        {
            int AlbumId = Convert.ToInt32(ddlAlbum.SelectedValue);

            LoadComboTrack(AlbumId);
        }

        protected void ddlTrack_SelectedIndexChanged(object sender, EventArgs e)
        {
            int TrackId = Convert.ToInt32(ddlTrack.SelectedValue);

            LoadGridViewCustomer(TrackId);
        }

Como se observa en el código, cada evento toma el id de la entidad que representa e inmediatamente después llama a la funcionalidad que carga el combo que le precede.

private void LoadComboArtist()
        {
            ddlArtist.DataSource = ChinookDAL.GellAllArtist();
            ddlArtist.DataTextField = "Name";
            ddlArtist.DataValueField = "ArtistId";
            ddlArtist.DataBind();

            if (ddlArtist.Items.Count != 0)
            {
                int ArtistId = Convert.ToInt32(ddlArtist.SelectedValue);

                LoadComboAlbum(ArtistId);
            }
            else
            {
                ddlAlbum.Items.Clear();
                ddlTrack.Items.Clear();
                dvCustomer.DataSource = null;
                dvCustomer.DataBind();
            }
        }

        private void LoadComboAlbum(int ArtistId)
        {
            ddlAlbum.DataSource = ChinookDAL.GellAlbumByArtist(ArtistId);
            ddlAlbum.DataTextField = "Title";
            ddlAlbum.DataValueField = "AlbumId";
            ddlAlbum.DataBind();


            if (ddlAlbum.Items.Count != 0)
            {
                int AlbumId = Convert.ToInt32(ddlAlbum.SelectedValue);

                LoadComboTrack(AlbumId);
            }
            else
            {
                ddlTrack.Items.Clear();
                dvCustomer.DataSource = null;
                dvCustomer.DataBind();
            }
        }

        private void LoadComboTrack(int AlbumId)
        {
            ddlTrack.DataSource = ChinookDAL.GellTrackByAlbum(AlbumId);
            ddlTrack.DataTextField = "Name";
            ddlTrack.DataValueField = "TrackId";
            ddlTrack.DataBind();

            if (ddlTrack.Items.Count != 0)
            {
                int TrackId = Convert.ToInt32(ddlTrack.SelectedValue);

                LoadGridViewCustomer(TrackId);
            }
            else
            {
                dvCustomer.DataSource = null;
                dvCustomer.DataBind();
            }
        }

        private void LoadGridViewCustomer(int TrackId)
        {
            dvCustomer.DataSource = ChinookDAL.GellCustomerByTrack(TrackId);
            dvCustomer.DataBind();
        }

Cada método invoca a la funcionalidad de la DAL (Data Access Layer), para recuperar la información.

Se valida que el combo tenga ítem, y en caso de tenerlos invoca la carga del control que sigue en la jerarquía de controles anidados.

En caso de no tener ítem, realiza el borrado de todos los controles que depende de este en la cascada.

 

Aclaraciones


La base de datos utilizada en el ejemplo fue obtenido del sitio codeplex: Chinook

Para poder ejecutar la aplicación simplemente deben tener el Sql Server Express corriendo en la PC local

 

[C#]
[VB.NET]

39 comentarios:

  1. ok... hay mucho ejemplos de la misma carecteristica... como se podria hacer si no tenemos un numero fijo de DropDownList, algo que sea dimamico...

    ResponderEliminar
  2. hola Norman

    disculpa la tardanza en responder

    El que sea dinamico no tendria tanta complicacion el tema sera a que evento de SelectedIndexChanged suscribir ese control para que informe la seleccion y cargue el siguiente combo

    Quizas se podria usar unico evento al cual se atachan todos los combos dinamicos y con algun valor compuesto en el SelectedValue se indicaria cual es el proximo control a cargar.

    Por supuesto la busqueda de ese control se haria tambien dinamica por medio del FindControl() en la Page

    Pero igual esto es solo una idea, habria que analizarlo mejor

    saludos

    ResponderEliminar
  3. Hola leandro, acabo de ver tu ejemplo, y eso más o menos es lo que yo quiero hacer pero con un CascadingDrpDown, pero me da Method error 500, ¿sabrías decirme a qué se debe?

    ResponderEliminar
  4. hola Angeles

    Bueno con el CascadingDropDown es bastante distinto de implementar, imagino has creado los servicio web que devuelven la info que carga la data de cada combo

    CascadingDropDown Demonstration

    Prueba de poner un breakpoint en los servicio y validar que no se generen problemas alli y se carga la info que retorna de forma correcta.

    Using CascadingDropDown with a Database

    saludos

    ResponderEliminar
  5. Hola Leandro,

    he implementado tu codigo pero en vez de artistas, albums y tracks, lo he hecho en tipos de producto, producto y rango de producto..

    lo que pasa es que al mostrar el grid con los rangos de podructo no puedo programar el evento paging changing porque no se a que función llamar y eso..

    me podrías ayudar? es un poco urgente.. muchas gracias por adelantadoo!

    ResponderEliminar
  6. hola Ramon

    el que tengas controles anidados no deberia afectar en nada al paginado del grid

    Este lo paginas comunmente, como menciono aqui

    http://social.msdn.microsoft.com/Forums/es/netfxwebes/thread/714178ec-726f-46c0-805c-c7b1028669cd

    veras que implementas el evento PageIndexChanging
    y en este evento no solo asignas la pagina a la cual se debe ir, sino que vuelves a asignar los datos para bidnear el grid.

    saludos

    ResponderEliminar
  7. Hola de nuevo Leandro..

    entiendo lo que quieres decir, y el funcionamiento del evento.. Lo que no sé.. es como volver a rellenar el grid..

    yo tengo una función que es:
    private void LoadGridViewIntervenciones(int id_cliente)
    {
    gvIntervenciones.DataSource = DB.GellInterventionsByCliente(id_cliente);
    gvIntervenciones.DataBind();
    }

    y en el evento que debo poner para rellenenar?

    protected void gvIntervenciones_PageIndexChanging(object sender, GridViewPageEventArgs e)
    {
    int newPageNumber = e.NewPageIndex + 1;
    -------
    ---------
    }

    Muchas gracias por adelantado y perdona por la ignorancia.. voy aprendiendo.. jeje

    ResponderEliminar
  8. hola Ramon

    algo como esto

    gvIntervenciones_PageIndexChanging(object sender, GridViewPageEventArgs e)
    {
    int newPageNumber = e.NewPageIndex + 1;
    LoadGridViewIntervenciones(Convert.ToInt32(txtisCliente.Text));
    }


    o sea tomas el id de la misma forma que lo has usado la primera vez para cargar, alli puse de ejemplo que se toma de un textbox
    pero si lo tienes en un Session tambien es valido

    saludos

    ResponderEliminar
  9. Hola como se podria anidar los dropdownlist usando linq un ejemplo de PAIS, ESTADO, CIUDAD

    ResponderEliminar
  10. hola charly

    usando linq ? te refieres a linq to sql

    la tecnica es la misma solo que el valor que tomas de la seleccion anterior la usas de filtro en el where de linq

    var result = from item in context.Estados
    where item.IdPais == cbpaises.SelectedValue
    select item;

    es un ejemplo por supuesto no digo que sea exatamente de esta forma pero como veras usas la seleccion como filtro

    saludos

    ResponderEliminar
  11. hola Leonardo, tengo una duda que hace esto:
    ChinookDAL.GellAllArtist();

    es que intento acomodar el código con el que yo tengo y todo va bien y entiendo cada cosa solo que esa parte no se que hace ni en que parte la creaste ...

    gracias : )!

    ResponderEliminar
  12. hola

    realiza una busqueda en toda al solucion por el nombre ChinookDAL

    deberias encontrar una clase definida como static, es alli donde esta el metodo para recuperar los artistas

    esa clase pertenece a la capa de datos

    saludos

    ResponderEliminar
  13. Hola Leandro buenas tardes.Quisiera saber como puedo almacenar el texto que cotniene el Dropdonwlist. Espero tu respuesta. Hasta luego.

    ResponderEliminar
  14. Hola Leandro. Qusiera almacenar el texto que contiene el DropDownList y no el Id. Espero tu pronta respuesta. Hasta luego.

    ResponderEliminar
  15. hola

    lamacenarlo donde ? en una db en un archivo de texto

    puedes tomar el texto del combo usando

    string cadena = DropDownlist1.SeletedItem.Text;


    saludos

    ResponderEliminar
  16. Hola Leandro, tengo ungridview con combos anidados que se deben editar, el detalle que tengo es que cuando estoy en modo edicion y cambio el valor del primer Dropdown me envia al evento editar del gridview en lugar del evento del combo. como puedo resolverlo? de anntemano agradezco tu ayuda

    ResponderEliminar
  17. hola Jessica

    lo primero que podria recomendar es que no anides controles dentro de un gridview, porque es para problemas

    al estar en control como contenedor de otro es logico que los eventos sean del control que los contiene, si defines la propiedad AutoPostBack = true en el dropdownlist deberias poder capturar ese evento, pero vas a necesitar tambine usar el

    NamingContainer

    para poder localizar el combo de que fila lanzo la accion y localizar el otro control que debes afectar

    como veras se podria hacer pero no es nada directo, por eso en estos casos tienedo a editar por fuera del grid seleccionando la row y editando en controles simples

    saludos

    ResponderEliminar
  18. Hola Leandro yo tengo un DropDownList que la edite con los meses solamente estos no estan cargados a ninguna bd. tengo una store procedure que me gustaria desplegarla al momento de seleccionar Enero me despligue en el grid todos los datos que tengo en ese mes, el problema aqui es que no me despliga la store procedure en el grid no logro verla, y de acuerdo a unos campos are una resta de fechas que no se como desplegar en cada fila del grid ni usar los eventos que explicas. No ce si me di a enternder ojala puedas ayudarme!!

    ResponderEliminar
  19. hola mElYnIt@

    ese procedure que dato recibe como parametro ? solo el numero del mes seleccionado en el combo o tambien un año en concreto

    como pasas los parametros al procedure cuando ejecutas, usas el Parameters del SqlCommand ?

    saludos

    ResponderEliminar
  20. Hola Leandro
    El codigo ejemplo no lo puedo bajar, como hago? Gracias

    ResponderEliminar
  21. hola Unknown

    ya esta actualizado para que puedas descargar el codigo

    saludos

    ResponderEliminar
  22. Como se hace con base de datos en sql

    ResponderEliminar
  23. hola edi ska

    pero alli se utiliza una base de datos sql server

    lo unico es que la forma de conectarse es por medio de un attach dinamico, si la idea es usar una db dentro del servicio de sql server solo debes definir el connection string que esta en web.config para que apunte a esa db

    saludos

    ResponderEliminar
  24. hola leandro, tengo una pregunta,
    tengo una pagina en donde uso dos dropdownlist, pero no logro que al seleccionar un item del primero me actualice el segundo,

    alguna sugerencia?

    ResponderEliminar
  25. hola eco

    asignaste la propiedad AutoPostBack en true del dropdownlist

    sino lo haces el evento de seleccion no se ejecuta

    saludos

    ResponderEliminar
  26. Que tal Leandro.
    Tengo el siguiene inconveniento, tengo un ddl pero al seleccionar un elemento y hacer el autoposback me devuelve siempre al mismo.

    < asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" OnTextChanged="DropDownList1_TextChanged" >

    < asp:ListItem Value="1" Text="Melon">< /asp:ListItem>
    < /asp:ListItem>
    < asp:ListItem Value="1" Text="Durazno">< /asp:ListItem>
    < asp:ListItem Value="1" Text="Pera">< /asp:ListItem>
    < /asp:DropDownList>

    < asp:Label ID="Label1" runat="server">< /asp:Label>

    ----------
    protected void DropDownList1_TextChanged(object sender, EventArgs e)
    {
    if (DropDownList1.SelectedValue == "1")
    {
    Label1.Text = " Valor = " + DropDownList1.SelectedValue + " Texto = " + DropDownList1.SelectedItem.Text;

    }

    else
    {
    Label1.Text = "No se selecciono nada";
    }
    }

    Ya le he intentado de mil formas pero no he logrado de solucionar.

    ResponderEliminar
  27. hola tengo una duda, me tira error una parte del codigo que cambie para acomodarlo al mio.

    private static Pais Cargar_Pais(IDataReader reader)
    {

    Pais item = new Pais();

    item.id_pais = Convert.ToInt32(reader["id_pais"]);
    item.pais = Convert.ToString(reader["pais"]);

    return item;

    }


    el error me da en id_pais y me dice: No se puede convertir un objeto DBNull en otros tipos.

    ResponderEliminar
  28. hola diego

    creo que esta pregunta la realizaste en el foro, pero no encontre donde

    por eso repito la repsuesta, un campo que indica un id o key d ela tabla no puede permitir nulos, sino deja de ser un id

    para campos nulos deberias validarlo

    if(reader["id_pais"] != DBNull.Value){
    item.id_pais = Convert.ToInt32(reader["id_pais"]);
    }

    solo asignas si el campo no tiene ningun null

    saludos

    ResponderEliminar
  29. hola jupemen

    en que evento cargas los datos del combo, lo haces en el Page_Load?
    porque si es asi recuerda que debes ponerlos dentro del

    if(!IsPostBack){
    //aqui cargas los datos
    }

    sino no pones dentro del if entonces se recargara por cada evento perdiendo la seleccion

    saludos

    ResponderEliminar
    Respuestas
    1. Correcto, se carga el primer drop, sin embargo cuando seleccionas un ítem de ese, deseas que se cargue el segundo de acuerdo a tu selección del primero, pero este se reinicia y queda en el primer ítem y no hay forma, si quitas el Autopostback entonces no se activa el segundo Drop. que problema con estos drop anidados o dependientes. Sugerencias..y gracias

      Eliminar
  30. Hola Leandro

    Te queria consultar, sobre dropdownlist anidados.

    Tengo un dropdownlist de inicio y 3 dropdownlist mas encadenados.

    Al momento de modificar los datos, rescato los valores para mostrar en pantalla y el primer combo que no tiene filtro, muestra bien, en cambio los dependientes no muestra debido a que no encuentra el valor.

    Probe haciendo databind al dataset y al dropdownlist y no me arroja error, pero no muestra elementos.

    Saludos

    ResponderEliminar
  31. hola guilledr

    defines correctamente las propiedades DataTextField y DataValueField del dropdownlist ?

    estas asignando el DataSource con un datatable, no uses dataset si solo vas a cargar una sola tabla, o sino usas ds.Tables[0] para asignar el datasource

    saludos

    ResponderEliminar
  32. Hola,

    este ejemplo es muy bueno siempre y cuando en el segundo combo tengas los datos cargados con todos los posibles registros, con el campo que relaciona con el combo 1, Pero si el segundo no necesariamente tiene todos los posibles, sino que depende de una búsqueda en el servidor dependiendo de lo que se halla seleccionado en el primero, creo que solo está la opción de updatepanel.

    ResponderEliminar
  33. hola Javier

    la verdad no entendi el planteo que realizas

    el updatepanel te ayudara a cargar los controles sin que se actualice toda la pagina, pero no se si es esto lo que buscas

    saludos

    ResponderEliminar
  34. y Como puedo hacerlo con tres DropDownList que tengo dentro del gridview y que cargue en cascada

    ResponderEliminar
  35. tu link de descarga esta caigo men, podria volverlo a subir?.

    ResponderEliminar
  36. Tu codigo me funciona, pero al selecionar el el segundo ddl(que no sea el de por defecto) que en tu caso seria el de album se me borran los otros dos, sabes porque?

    ResponderEliminar
  37. Correcto, se carga el primer drop, sin embargo cuando seleccionas un ítem de ese, deseas que se cargue el segundo de acuerdo a tu selección del primero, pero este se reinicia y queda en el primer ítem y no hay forma, si quitas el Autopostback entonces no se activa el segundo Drop. que problema con estos drop anidados o dependientes. Sugerencias..y gracias

    ResponderEliminar