Llenar un DropDownList en una GridView

Hay una manera muy simple de llenar un combo, ya sea con los mismo valores o con distintos, en cada fila de una GridView en ASP.NET 2.0 (VS 2005). Lo primero que hay que hacer es (obviamente) dropear una gridview en la pagina y al insertar las columnas a la que queremos que sea nuestro combo la convertimos en Template de esta manera:

foto1.jpg

Hecho esto vamos a editar nuestro Template asi:
foto2.jpg

SIN USAR EDITITEMTEMPLATE

Dentro de ItemTemplate vamos a eliminar el Label que nos viene por defecto y dropear un DropDownList, no hace falta hacerlo en EditTemplate. Nos queda algo asi:
foto3.jpg

Al termina la edición nos queda algo asi:
foto4.jpg

Ahora nos pasamos a la parte HTML de la pagina para ver como nos queda la grilla:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="4"

           ForeColor="#333333" GridLines="None">

           <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />

           <Columns>

               <asp:BoundField DataField="nomCom" HeaderText="Nombre" />

               <asp:TemplateField HeaderText="Cargo">

                   <EditItemTemplate>

                       <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>

                   </EditItemTemplate>

                   <ItemTemplate>

                       <asp:DropDownList ID="DropDownList1" runat="server" Width="179px" DataTextField="CARGO" DataValueField="ID">

                       </asp:DropDownList>

                   </ItemTemplate>

               </asp:TemplateField>

           </Columns>

           <RowStyle BackColor="#EFF3FB" />

           <EditRowStyle BackColor="#2461BF" />

           <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />

           <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />

           <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />

           <AlternatingRowStyle BackColor="White" />

       </asp:GridView>

En mi caso todos los combos se llenan con la misma información por eso agrego el DataTextField ahí, esto se podría hacer del lado servidor.
Ahora lo mas importante del código esta en el evento RowDataBound de la grilla y es algo muy simple:

Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound        Try

            If e.Row.RowType = DataControlRowType.DataRow Then 'DataRow Vale las row que tienen datos, de esta manera se saltea el header,el footer y el pager

                Dim ddl As DropDownList

                Dim dt2 As DataTable = LlenarTabla2()

                'Celda 1 es donde esta el DropdownList

                Dim gvrow As GridViewRow = CType(e.Row.Cells(1).NamingContainer, GridViewRow)

                ddl = CType(gvrow.FindControl("DropDownList1"), DropDownList)

                ddl.ClearSelection()

If ddl IsNot DBNull.Value Then

                    ddl.DataSource = dt2

                    ddl.DataBind() 'Lleno el combo

                End If

                'Después de llenar el combo se puede asignar el valor si es que tenia uno

                'aca haciendo ddl.ddl.SelectedValue =...

            End If

        Catch ex As Exception

            Throw ex

        Finally

End Try

    End Sub

Al ejecutar el proyecto la pagina nos queda de esta manera.

foto5.jpg

Adjunto el proyecto aqui.

USANDO EDITITEMTEMPLATE

También se pueden usar las hermosas características que nos proporciona .NET 2.0 y usar la columna CommandField con los botones de Editar y Actualizar.

En este caso el HTML nos quedaría de esta manera:

<asp:GridView  ID="GridView2"  runat="server"

            OnRowCancelingEdit="GridView2_RowCancelingEdit"  OnRowEditing="GridView2_RowEditing"

            DataKeyNames="ID"  OnRowUpdating="GridView2_RowUpdating"  OnRowUpdated="GridView2_RowUpdated"

            ShowFooter="True"  CellPadding="4" ForeColor="#333333" GridLines="None" AutoGenerateColumns="False" >

        <Columns>

                <asp:BoundField DataField="nomCom" HeaderText="Nombre" />

                <asp:TemplateField HeaderText="Cargo">

                    <EditItemTemplate>

                        <asp:DropDownList ID="DropDownList1" runat="server" Width="179px" DataTextField="CARGO" DataValueField="ID">

                        </asp:DropDownList>

                    </EditItemTemplate>

                    <ItemTemplate>

                    <asp:Label ID="CargoText" runat="server" Text='<%# Eval("Cargo") %>'></asp:Label>

                    </ItemTemplate>

                </asp:TemplateField>

                <asp:CommandField ShowEditButton="True" EditText="Editar" />

            </Columns>

             <FooterStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White" />

             <RowStyle BackColor="#E3EAEB" />

             <EditRowStyle BackColor="#7C6F57" />

             <SelectedRowStyle BackColor="#C5BBAF" Font-Bold="True" ForeColor="#333333" />

             <PagerStyle BackColor="#666666" ForeColor="White" HorizontalAlign="Center" />

             <HeaderStyle BackColor="#1C5E55" Font-Bold="True" ForeColor="White" />

             <AlternatingRowStyle BackColor="White" />

    </asp:GridView>

La primer diferencia es que el Dropdownlist ahora está dentro de una Tag edititemtemplate, esto es porque el combo no va aparecer desde un principio con el ejemplo anterior sino que solo se va a renderear para la row que quiera editar. Y que se mostrará en su lugar? Buena pregunta, para eso está el ItemTemplate que muestra algo por defecto en todas las rows o como en mi caso el valor de “Cargo” (esto va a salir del datatable que llenará la grilla, le agrego un valor por defecto).

Ahora vamos al código en VB en este caso no solo voy a necesitar RowDataBound sino también el evento RowEditing (el que entrará en acción cuando el usuario de click a la row):

Partial Class _Default

    Inherits System.Web.UI.Page

    Dim dt1 As DataTable = LlenarTabla1()

    Dim ht As Hashtable

    Dim flag As Boolean = FalseProtected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Try

            If Not Page.IsPostBack Then

                dBindData()

            End If

        Catch ex As Exception

            Throw ex

        End Try

    End Sub

Sub dBindData()

      GridView2.DataSource = dt1

      GridView2.DataBind()

End Sub

Protected Sub GridView2_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView2.RowDataBound

       Try

           If e.Row.RowType = DataControlRowType.DataRow Then 'DataRow Vale las row que tienen datos, de esta manera se saltea el header,el footer y el pager

               Dim ddl As DropDownList

               Dim dt2 As DataTable = LlenarTabla2()

               'Celda 1 es donde esta el DropdownList

               Dim gvrow As GridViewRow = CType(e.Row.Cells(1).NamingContainer, GridViewRow)

               ddl = CType(gvrow.FindControl("DropDownList1"), DropDownList)

If ddl IsNot Nothing Then

                   ddl.ClearSelection()

                   If ddl IsNot DBNull.Value Then

                       ddl.DataSource = dt2

                       ddl.DataBind() 'Lleno el combo

                   End If

                   If flag = True Then

                       'si no esta vacio la hashtable se lo asigno al combo

                       If Not String.IsNullOrEmpty(ht.Item(1)) Then ddl.SelectedValue = ddl.Items.FindByText(ht.Item(1)).Value

                   End If

               End If

End If

       Catch ex As Exception

           Throw ex

       Finally

End Try

   End Sub

Protected Sub GridView2_RowEditing(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs) Handles GridView2.RowEditing

       Dim idIndex As Integer = e.NewEditIndex

       Try

           GridView2.EditIndex = idIndex

           Dim lblTexto As Label = GridView2.Rows(idIndex).Cells(1).FindControl("CargoText")

           Dim ddl As DropDownList = GridView2.Rows(idIndex).Cells(1).FindControl("DropDownList1")

           If lblTexto IsNot Nothing Then

               'Guardo un Hash con el valor que tiene el Label

               ht = New Hashtable

               'siempre en el value 1 porque lo voy a usar solo para un valor

               ht.Add(1, lblTexto.Text)

           End If

           'uso el flag para saber cuando esta rendereando 

           'el EditTemplate y no el Itemtemplate

           If ddl IsNot Nothing Then flag = True

           GridView2.DataSource = LlenarTabla1()

           GridView2.DataBind()

       Catch ex As Exception

           Throw ex

       Finally

End Try

End Sub

End Class

Uso una HashTable para almacenar el valor que voy a tener que setear en el DropDownList una vez seleccionado, sino siempre mostraría el 1er valor del Combo.

Dejo este 2do ejemplo para descargar aca

Saludos.