Cómo acceder a controles dentro de un GridView
Esta entrada salió como resultado de una pregunta que hicieron en el Foro de la Comunidad .NET. La pregunta, esencialmente, es: ¿Cómo accedo a un control que tengo en una columna templeteada dentro de un GridView de ASP.NET?
Me pareció buena la pregunta, así que hice un pequeño ejemplo para ilustrarlo. Una columna templeteada (TemplateField) es distinta a una normal (BoundField) en que tienes más control sobre los controles que aparecen en la columna. En otras palabras, tú especificas qué quieres que se muestre cuando el renglón está en modo "normal" (ItemTemplate) o cuando está en modo "edición" (EditItemTemplate). Puedes tener múltiples controles dentro de la columna, en lugar de solo uno que represente el dato.
La siguiente página contiene un GridView con tres columnas que vienen de un SqlDataSource. Los datos provienen de la clásica base de datos Northwind. En este caso estoy recuperando datos de la tabla de productos:
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb"
Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Accediendo a Elementos en un GridView</title>
<style type="text/css">
#miGrid
{
width: 450px;
float: left;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:Button runat="server" ID="leerElementosButton" Text="Leer elementos" />
<div id="miGrid">
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="SqlDataSource1"
EmptyDataText="No hay registros que mostrar.">
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="ID Producto"
InsertVisible="False" ReadOnly="True" />
<asp:BoundField DataField="ProductName" HeaderText="Nombre Producto" />
<asp:TemplateField HeaderText="Descontinuado">
<EditItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server"
Checked='<%# Bind("Discontinued") %>' />
</EditItemTemplate>
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server"
Checked='<%# Bind("Discontinued") %>' Enabled="false" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
ProviderName="<%$ ConnectionStrings:NorthwindConnectionString.ProviderName %>"
SelectCommand="SELECT [ProductID], [ProductName], [Discontinued] FROM [Products]">
</asp:SqlDataSource>
</div>
<div id="resultados">
<asp:Label runat="server" ID="resultadosLabel" />
</div>
</form>
</body>
</html>
Para acceder, por ejemplo, al CheckBox que está dentro de la columna templeteada, primero necesitas una referencia al renglón, ya que el ID del control se repetirá n veces (una por cada renglón del Grid).
Esto se puede hacer de varias formas, por ejemplo, si tienes un manejador para un evento clic en alguno de los controles dentro del renglón pues en ese caso el sender viene siendo el renglón en sí, entonces únicamente te falta encontrar el CheckBox de ese renglón para leer sus propiedades. Otra forma de hacerlo, como en el siguiente ejemplo, es leer todos los renglones y por cada uno encontrar el CheckBox que le corresponde al renglón:
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub leerElementosButton_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles leerElementosButton.Click
Dim grid As GridView = Me.GridView1
Dim checkBox As CheckBox
Dim resultado As New StringBuilder
For Each renglon As GridViewRow In grid.Rows
checkBox = CType(renglon.FindControl("CheckBox1"), CheckBox)
If checkBox.Checked Then 'Hacer algo con esta información
resultado.Append(String.Format( _
"El renglón {0} está descontinuado <br />", renglon.DataItemIndex))
End If
Next
resultadosLabel.Text = resultado.ToString()
End Sub
End Class
En resúmen, la idea clave aquí es que el GridView tiene una colección de renglones (de tipo GridViewRow) y cada uno de estos renglones tiene su correspondiente colección de controles que están dentro de ese renglón. El GridViewRow también te da acceso al DataItem que contiene los datos asociados al renglón, en caso de que lo requirieras.
El resultado de correr el código anterior (dando clic al botón) es el siguiente:
Espero les ayude.
Enjoy ![]()
Por RSS o Atom


Muy bien... pero como puedo manejar los eventos de los controles dentro de un item template de un gridview?
Sencillo, agregas un "handler" a tu control, como cualquier otro.
Por ejemplo, podrías hacerlo en el Page_Load:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Me.Load
For Each renglon As GridViewRow In GridView1.Rows
Dim checkBox As CheckBox = CType(renglon.FindControl("CheckBox1"), CheckBox)
If Not checkBox Is Nothing Then
AddHandler checkBox.CheckedChanged, AddressOf CheckBox1_CheckedChanged
End If
Next
End Sub
Esto asume, claro, que tienes un manejador como este:
Protected Sub CheckBox1_CheckedChanged(ByVal sender As Object, _
ByVal e As System.EventArgs)
Dim checkBox As CheckBox = sender
resultadosLabel.Text = _
String.Format("Diste clic al checkbox en el renglon {0}. El checkbox esta palomeado: {1}.", _
CType(checkBox.Parent.Parent, GridViewRow).RowIndex + 1, checkBox.Checked)
End Sub
Buen articulo, muy util para quienes utilizamos al maximo la potencialidad de una grilla...
Hola que tal carlos probe eso de manejar los eventos de los controles en un gridview y el ejemplo que pones del handles no me funciona me marca un error cuando hago AddHandler checkBox.CheckedChanged, AddressOf CheckBox1_CheckedChanged no me ponel el CheckedChanged y si lo dejo asi me dice que no es un evento del checkbox, el detalle es que quiero que cuando se chequea un checkbox actualice mi base de datos, el detalle es que al hacer esto me imagino que no se seleciona ninguna row entonces no puedo obtener el valor del datakey que es mi indice con el cual realizo el update , espero que me puedas echar la mano por que ya llevo 2 dias y no puedo hacerlo jajajajaja (me rio de mi mismo). de antemano muchas gracias . a y que interesante tu blog la neta, espero aprender mucho de ustedes ya que no soy muy bueno en esto de asp.net
Hola, muy bueno el articulo, estoy tratando de utilizarlo para un problema que tengo en el trabajo, voy creando dinamicamente imageButtons, que estan enlazadas a labels, y quiero que cuando pinche ese imagebutton me vuelva a eliminar el label creado y el propio imagebutton, lo de eliminarlos es facil, pero no me va al evento cuando hago click, no se porque puede ser...¿alguna idea?
Sergio--
Dependiendo de cómo esté configurada tu página (¿AutoEventWireup="true" o "false"?) a veces se batalla un poco para que agregue correctamente los manejadores de eventos. Me he topado con casos que tienes que hacerlo en el evento Init o Page_Load para que los agregue correctamente después de cada postback.
Genial, así da gusto!!
Muchas gracias!!
Si, finalmente lo he hecho en el page load, mediante una coleccion de controles que esta declarada como privada voy metiendo dinamicamente todos los imagebuttons y los labels, dandole el mismo número de id, es decir si elimino mi imgbtn0 se que tengo que eliminar el lbl0, asi es mucho mas facil, se que no se van a crear muchos y son faciles de controlar, ya que doy el mismo evento click a todos los imagebutton.Gracias por la ayuda, un saludo.
Disculpa Carlos, tengo problemas con un grid que tiene una columna de checkbox, quiero que al presionar un boton identifique los checkbox que estan seleccionados, pero siempre me regresa false.
De antemano, gracias por tu ayuda
Hola, seguramente sera porque no tienes el ViewState de algun elemento activado, comprueba que el viewstate del grid este a true, y si tiene algun contenedor mas ese checkbox tambien. ¿Como recorres el grid?