viernes, 23 de enero de 2009

Seleccionar por filas en un GridView

Hay días en que uno se siente "con la musa" y se siente bastante feliz por esos pequeños desarrollos que hacen la vida más fácil.

Mi control preferido, el GridView, me ha dado una nueva alegría al conseguir el siguiente requerimiento del cliente:

Dado un, que se pueda pinchar en una fila y que se abra la ventana de detalle.

En principio esto lo hacíamos con los dos consabidos botones de edición y borrado. Pero el cliente nos pidió si se podía realizar pinchando en la fila en sí.

Me dí un garbeo por San Google y entre un buen número de páginas y técnicas me quede con esta.


Protected Sub GridView_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView.RowDataBound
'' Si es una fila de datos.
If e.Row.RowType = DataControlRowType.DataRow Then
'' Cargo el comportamiento en cada fila.
e.Row.Attributes.Add("onclick", Page.ClientScript.GetPostBackEventReference(sender, "Acción$" & CType(e.Row.FindControl("idcontrol"), Label).Text))
'' Le indico que en utilice el cursor de selección cuando se pase por encima.
e.Row.Style.Add("cursor", "hand")
End If
End Sub



Como ves, el código es simple. En el evento que se lanza cada vez que cargo los datos en una fila del Grid, le añado un evento "onclick" el cual hace un postback que será capturado por el evento RowCommand del propio Grid.

Aquí, las dos cosas que hay que tener cuidadín son las que he resaltado en negrita. Es decir, le tienes que pasar el nombre del comando (CommandName) para poder tener el control de lo que va a ocurrir al pulsar en la fila. (si pones edit o delete o select o etc., tendrá el comportamiento por defecto de cualquier Grid). Y le tienes que indicar (por lógica) cual es el control en el que has cargado el identificador de los datos sobre los que quieres funcionar. En este caso, el identificador en la base de datos de un registro.

Por lo cual en el GridView tendras que añadir o seleccionar la columna que va a proveer el indice de identificación. En este ejemplo, es un Id en una columna oculta y es algo así:


<asp:TemplateField HeaderText="id" Visible="False">
   <ItemTemplate>
      <asp:Label ID="idControl" runat="server" Text='<%# eval("id").toString %>' runat="server" />
   </ItemTemplate>
</asp:TemplateField>


Y ahora me voy a mi evento RowCommand de mi Grid y le añado un condicional para capturar el evento que he añadido en el onlick.


Protected Sub GridView_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles GridView.RowCommand
Select Case e.CommandName
Case "Acción"
'' Aquí hace cosas
End Select
End Sub


Jo!! Que bien funciona... peeeeero (siempre hay uno) y aquí viene mi aportación al mundo del desarrollo :), me veo que se superpone el comportamiento de la fila sobre el comportamiento esperado del botón de borrar (el cual no me quiero llevar al detalle). arrggg!!.

Pues, dándole unas poquillas vueltas, me doy cuenta que así como trato sobre la fila entera, puedo hacerlo un poco más granular y aplicar el comportamiento sobre las celdas, dejando fuera las que yo quiera que se comporten de otra forma.

Solución en el siguiente código en donde solamente he cambiado la linea de carga del atributo onclick por un bucle que carga dicho atributo a cada una de las filas excepto la última, que es donde tengo situado el botón de borrado.


Protected Sub GridView_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView.RowDataBound
Dim numCeldas As Integer
'' Si es una fila de datos.
If e.Row.RowType = DataControlRowType.DataRow Then
''Cuento el número de celdas que componen la fila.
numCeldas = e.Row.Cells.Count

'' Cargo el comportamiento en cada celda.
'' En este caso en todas menos en la última que es la de borrado.
For x As Integer = 0 To numCeldas - 2
e.Row.Cells(x).Attributes.Add("onclick", Page.ClientScript.GetPostBackEventReference(sender, "Accion$" & CType(e.Row.FindControl("IdControl"), Label).Text))
Next

'' Le indico que en utilice el cursor de selección cuando se pase por encima.
e.Row.Style.Add("cursor", "hand")
End If
End Sub


Y lo mejor de todo, de todo es que funciona de muerte. Perfecto y de una forma muy poquito vista en la Web.

9 comentarios:

Anónimo dijo...

Hola mi nombre es Marco y estoy haciedno un proyecto en el cual eso el gridview pero en uno de los campos puse un textbox, quiero pasar la informacion de ese gridview a otro gridview al momento que le de click al boton seleccionar, alguien tiene algo parecido que pueda ayudarme , se los agradezco
mi correo es legion_sn07@hotmail.com

Juan Quijano dijo...

No es dificil. En el rowDataBound busca el control del textBox y cargalo en una propiedad que tenga persistencia (por clase estática, por variable de seción o por viewstate) y despúes lo recoges en el nuevo Grid.

p.d. no pidas código... eso te toca a ti ;D

magicart dijo...

Hola, mi nombre es Arturo. Me a servido mucho la explicación que montaste en tu blog, ahora quiero hacer una pequeña modificación y creo que estoy haciendo algo mal. Veras, el evento "onclick" quiero agregarle un método que tengo, por ejemplo: gvSinergias_SelectedIndexChanging. (ojo que puede ser un método XXXX). Ahora, cuando lo ejecuto me dice que el método no existe. alguna sugerencia???

Juan Quijano dijo...

El método más sencillo que he encontrado para saber si existe un evento como el que quiero es mirar en el propio Visual Studio cuales son los métodos del objeto (en este claso el DataGridView).

Otra forma, que no me acuerdo si la he publicado, es definiendo tu propio método e incluyendolos en los métodos de "Select, Edit o Delete" del DataGridView, e invocandolo.

Anónimo dijo...

Buenas tardes, yo tengo una fila que tiene el atributo onclic para ir a una determinada pagina.
En la ultima columna tiene un combo
en esa columna necesito decirle si el onclic viene de ahi, no ejecutes esos atributos.

Porque sino al hacer clic me va directamente a otra pagina.
Gracias - Gabriela

Juan Quijano dijo...

Gabriela, he insertado un nuevo artículo en el blog proponiedo una solución: http://1poquitodtodo.blogspot.com/2010/07/gridview-onclick-condicionales.html

Azul7777 dijo...

que tal buenas tardes.
Estoy haciendo una aplicacion web para una escuela.
Tengo un gridview "Noticias.aspx" y tengo el titulo de la noticia como "buttonField" que enlaza a la pagina de "verNoticia.aspx".
Lo que quiero es que al seleccionar el titulo de cualquier noticia me aparezca la descripcion en la pagina "VerNoticia.aspx"

Los campos de mi grid view son:
NoticiaID (no visible)
Titulo url (buttonfield)
Descripcion (no visible)
fecha (visible)
imagen (visible)

agradezco sus respuestas

Sebastian Edgardo Kinderman Fuentealba dijo...

Hola, que hace "CType"?? estoy intentando hacer lo mismo, pero no se que hace eso.

Anónimo dijo...

Hola, Mi nombre es Juan, me ha parecido bastante interesante los consejos. Tengo un problema con el GridView, he colocado un GridView dentro de un "Div" para pode hacer el scroll vertical por el tamaño del mismo, pero al momento que selecciono una fila que esta varias filas abajo, la vista cambia a mostrame las primeras filas, ocultando la seleccionada. hay alguna forma de mantener la vista en la zona seleccionada?, alguna alternativa al uso del "Div"? Gracias de antemano.