domingo 12 de junio de 2011

[ASP.NET][GridView] - Como seleccionar una fila

 

Introducción

He visto en reiteradas oportunidad que una operación simple como es el caso de operar con una fila de un GridView se puede transformarse en algo complejo, mas que nada motivado por la distintas formas que hay para realizar esta acción.

En este articulo veremos las algunas formas de lograrlo y como difieren las técnicas que se puede aplicarse.

Temas que se tratar:

1- Seleccionar una Row

a- Definiendo un CommandField

b- Usando un ImageButton y CommandName

c- Usando el evento RowCommand

2-Uso de DataKeyNames y DataKeys

   a- DataKeyNames con campos Múltiples

Para todos los casos planteados partiremos del mismo gridview, el cual se ira modificando para agregarle opciones y ver los distintos temas.

 

1- Seleccionar una Row

Existen varias formas de realizar una misma tarea, pero veremos aquí las dos mas simples y directas que se suelen encontrar cuando se necesita seleccionar un registro en el control gridview.

1a- Definiendo un CommandField

Iremos realizando los paso de forma visual así se comprende como proceder, remarcando luego como impacta esto en el html del grid

El primer paso será editar las columnas del GridView hasta visualizar el cuadro con las opciones de CommandField disponibles.

Para este caso en particular se agregara solo la opción de selección. Mediante las flechas laterales se puede posicionar el comando. También se dispone de distintos tipos de representación visual, como ser un Link, Button o Image.

Para este caso usaremos un comando del tipo Image, por lo tanto se deberá definir la propiedad “SelectImageUrl”. Si se define del tipo Link y se quiere cambiar el texto, se usaría la propiedad “SelectText”.

El próximo paso será el de definir el evento de selección, para esto solo marcamos el gridview, y yendo a sus propiedades se podrá activar el evento SelectedIndexChanged

El html resultante debería tener resaltadas las siguiente características

Con estos pasos ya estamos listos para capturar la acción de selección del gridview.

 

1b - Usando un ImageButton y CommandName

En esta alternativa se hará uso de un TemplateField, se prodece de la misma forma del paso 1a, pero se agrega un item diferente

Una vez que esta el témplate, se adapta modificando directamente en el html, incluyendo de esta forma el control ImageButton.

Es muy importante remarcar que el ImageButton deberá tener la propiedad CommandName=”Select” para que esta ejecute el evento SelectedIndexChanged

A nivel de código de la pagina se encontrara la definición del evento

Hay que aclarar que en este caso se uso un ImageButton para corresponder con la acción del punto 1a, en donde se define una imagen, pero si se requiere de un link solo será cuestión de usar un LinkButton, definiendo en este el CommandName=”Select”, es justamente el CommandName quien define que evento será lanzado al presionarse.

 

1c- Usando el evento RowCommand

Seguramente a estas alturas se preguntaran que cantidad de formas de hacer lo mismo, asi es, y para completarlo una opción extra.

Resulta que al definir un ImageButton (o LinkButton) en un TemplateItem y usar el CommandName=”Select” se habilita un evento adicionar para poder capturar esta acción, si es que el SelectedIndexChanged no nos convence.

Se trata del evento RowCommand.

Hay un pequeño detalle con este evento y se trata de la definición del CommandArgument para determinar que fila lanza la acción.

[C#]

protected void gvPerson_RowCommand(object sender, GridViewCommandEventArgs e)
{
    if (e.CommandName == "Select")
    {
        //
        // Se obtiene indice de la row seleccionada
        //
        int index = Convert.ToInt32(e.CommandArgument);
        
        //
        // Obtengo el id de la entidad que se esta editando
        // en este caso de la entidad Person
        //
        int id = Convert.ToInt32(gvPerson.DataKeys[index].Value); 

    }

}

[VB.NET]

Protected Sub gvPerson_RowCommand(sender As Object, e As GridViewCommandEventArgs)
	
        If e.CommandName = "Select" Then
		'
		' Se obtiene indice de la row seleccionada
		'
		Dim index As Integer = Convert.ToInt32(e.CommandArgument)

		'
		' Obtengo el id de la entidad que se esta editando
		' en este caso de la entidad Person
		'

		Dim id As Integer = Convert.ToInt32(gvPerson.DataKeys(index).Value)
	End If

End Sub

En el ejemplo de la pagina WebForm4.aspx, se podrá probar como ambos eventos, tanto el RowCommand y el SelectedIndexChanged, pueden definirse, aunque lo normal es utilizar solo uno de estos.

 

2 - Uso de DataKeyNames y DataKeys

Una de las mejores técnicas usada para detectar que entidad se esta editando o seleccionado es por medio de id o código que esta tenga asignada, pero como logar hacerlo sin mostrar el identificador al usuario en una columna ?, es justamente el trabajo de estas dos propiedades que se consigue resolver el problema.

Si se presta atención al html este contaba con al definición de esta propiedad de nombre DataKeyNames

Solo debe definirse que campo del origen de datos identifica a la entidad que se esta trabajando.

Cuando se lance el evento solo será cuestión de tomar la row que ejecuta la acción, y de esta, por el índice recuperar el valor del id de la entidad, en este caso el PersonID.

[C#]

protected void gvPerson_SelectedIndexChanged(object sender, EventArgs e)
{
    //
    // Se obtiene la fila seleccionada del gridview
    //
    GridViewRow row = gvPerson.SelectedRow;

    //
    // Obtengo el id de la entidad que se esta editando
    // en este caso de la entidad Person
    //
    int id = Convert.ToInt32(gvPerson.DataKeys[row.RowIndex].Value);


}

[VB.NET]

Protected Sub gvPerson_SelectedIndexChanged(sender As Object, e As EventArgs)
	'
	' Se obtiene la fila seleccionada del gridview
	'
	Dim row As GridViewRow = gvPerson.SelectedRow

	'
	' Obtengo el id de la entidad que se esta editando
	' en este caso de la entidad Person
	'
	Dim id As Integer = Convert.ToInt32(gvPerson.DataKeys(row.RowIndex).Value)


End Sub

2a- DataKeyNames con campos Múltiples

En este ejemplo solo se utilizo un valor simple para identificar a la entidad, pero el CommandName puede definir mas de un campo de información.

Por ejemplo que sucede si se quiere enviar el PersonId y el Nombre, esto es tan solo un ejemplo para demostrar las funcionalidad, no tiene una aplicación práctica en este caso, ya que con solo el PersonID seria mas que suficiente.

Para definir el DataKeyNames en el grid es tan simple como separar los campos por una coma.

y en el código solo se toma el valor de la propiedad Values

[C#]

protected void gvPerson_SelectedIndexChanged(object sender, EventArgs e)
{
    //
    // Se obtiene la fila seleccionada del gridview
    //
    GridViewRow row = gvPerson.SelectedRow;

    //
    // Obtengo el id y el nombre  de la entidad que se esta editando
    // en este caso de la entidad Person
    //
    int id = Convert.ToInt32(gvPerson.DataKeys[row.RowIndex].Values["PersonID"]);

    string nombre = Convert.ToString(gvPerson.DataKeys[row.RowIndex].Values["FirstName"]);


}

[VB.NET]

Protected Sub gvPerson_SelectedIndexChanged(sender As Object, e As EventArgs)
	'
	' Se obtiene la fila seleccionada del gridview
	'
	Dim row As GridViewRow = gvPerson.SelectedRow

	'
	' Obtengo el id y el nombre  de la entidad que se esta editando
	' en este caso de la entidad Person
	'
	Dim id As Integer = Convert.ToInt32(gvPerson.DataKeys(row.RowIndex).Values("PersonID"))

	Dim nombre As String = Convert.ToString(gvPerson.DataKeys(row.RowIndex).Values("FirstName"))


End Sub

Ejemplo Código

Para el ejemplo se hizo uso de Visual Studio 2008 con SP1, el service pack es útil para poder hacer uso de Entity Framework y poder crear el ADO.NET Entity Data Model haciendo simple el acceso a la db.

La base de datos es Sql Server 2008 Express R2, y se encuentra el mdf dentro de la carpeta App_Data, pero se podría adjuntar al servicio de Sql Server o hacer uso del script que se encuentra en el proyecto de DataAccess.

 

 

22 comentarios:

Augusto dijo...

Leandro no he podido ejecutar tu ejemplo cuales son los requisitos tengo visual studio 2008 y sql 2005

Leandro Tuttini dijo...

hola Augusto

Justo arriba del link menciono lo que use para desarrollarlo:
VS2008 SP1 y SQL Server Express R2
sino puedes tomar el script y ejecutarlo para crear la db en sql2005

saludos

jor ge dijo...

leandro como estas, te cuento que estoy desarrollando una aplicacion pero mi duda es en el momento de ejecutar una insercion en una tabla como se valida el campo clave para que no me repitan el mismo valor de la llave primaria para que no me rebiente el programa el error de la base de datos te agradeceria cualquier ayuda gracias

Leandro Tuttini dijo...

hola jorge

Te comento que la solucion a este problema puede evitar si validas previamente si existe o no la entidad con ese id (o codigo) en particular.

Revisa el artículo

[ADO.NET] – Parte 5 - Ejemplos Simples – Operaciones CRUD

Alli veras un metodo de nombre Exist() analiza el codigo que uso en este y veras como validar si ese id existe y poder actuar en consecuencia, o sea en el ejemplo si existe actualiza, sino existe inserta

saludos

Alexandra dijo...

Hola Leandro, tengo el siguiente problema cuando intento probar el ejemplo :"El tipo o el nombre del espacio de nombres 'Objects' no existe en el espacio de nombres 'System.Data' (¿falta una referencia de ensamblado?)" y todos los errores de este tipo apuntan a este archivo :
"School.Designer.cs" y también he notado que no se reconoce la referencia a System.Data.Entity . Alguna idea de como podría solucionarlo.
Gracias

Leandro Tuttini dijo...

hola Alexandra

Has verificado si tienes instalado el SP1 del VS2008 ?

lo pregunto porque sino recuerdo mal para poder usar Entity Framework requieres de service pack

lo que me extraña es lo del Object, pero puede deberse a un problema causado por otro errores, primero validaria si no es el SP, como para descartar este punto

si ingresas al edmx, puedes ver el diseño del Entity Framework

saludos

Alexandra dijo...

Ok,tenias razón necesitaba SP1, una vez instalado se soluciono todo, ahora solo me quedan dos dudas:
1. Cuando haces uso del CommandArgument le pasas el indice de la fila asi: "<%# ((GridViewRow)Container).RowIndex %>", pero si hago eso obtengo este error : : "'GridViewRow' es un tipo y no se puede usar como expresión." y por eso he tenido que usar esto para pasar el indice de la fila: "<%# Container.DataItemIndex %>". Lo curioso es que en el archivo que descargue de tu blog funciona correctamente, tiene algo que ver que el tuyo este es C# y el mio en VB??

2. He notado que siempre que vas a usar un evento de un control,en este caso onselectedindexchanged y onrowcommand, lo indicas en el markup de la pagina,sin embargo también he notado que si los quito no se ve afectado el funcionamiento del evento y me gustaría saber si tiene alguna utilidad colocarlos también en el html??

Saludos

Leandro Tuttini dijo...

hola Alexandra

1-
Claro, el tema es que en este articulo no he puesto el ejemplo en vb.net
y justamente alli cambia, en vb.net deberias ser:

DirectCast(Container, GridViewRow).RowIndex


2 -
si estas programando en vb.net puede que esto tenga algo que ver

valida si justo a la definicion del metodo en el codigo vb.net no defines un Handles, algo como ser:

Protected Sub gvPerson_SelectedIndexChanged(sender As Object, e As EventArgs) Handles gvPerson.SelectedIndexChanged

si logras ver que esta asi declarado, es porque vb.net ya adjunta el evento de esta forma

saludos

Andrea dijo...

Gracias!! alfin me funciono! era justo lo que necesitaba ^^

Fabi dijo...

Gracias!!!...no sabes como me sirvio

AlberCD dijo...

Leandro muy buena tu publicación, tengo una duda mas o menos relacionada. si deseas que al momento de seleccionar una fila del gridview se ejecute un codigo html, como le harias? o mejor dicho, se puede?

Leandro Tuttini dijo...

hola AlberCD

bueno en realidad habria que ver a que llamas ejecutar, imagino que sera visualizar esa pagina

en ese caso en el evento tal cual se explica en el articulo podrias usar el:
Response.Redirect("pagina.html")

con eso mostraria en la pantalla la pagina html

saludos

Marcelo dijo...

Hola Leandro, excelente tu artículo, pero tengo una duda...en un gridview con checkboxs, cómo hago para conocer el rowIndex del checkbox presionado?
Esa es mi duda, muchos saludos,
Marcelo.

Blog Personal dijo...

Excelente post, felicitaciones.. así deberían ser de claros todos los posts que hay en la red...

Javs dijo...

Muchas gracias, me fue muy útil!

Leandro Tuttini dijo...

hola Marcelo

el rowindex es algo concerniente al gridview no al check, este no tiene ningun rowindex por eso lo que tu recorres son las rows del grid

para luego buscar el check que contiene cada row que recorres y validas si esta marcada

pero el rowindex es de la instancia del row que en ese momento se este iterando

saludos

Cefer dijo...

Saludos.

Estimado por solicitar ayuda ya que tengo un proyecto en el cual tomo la información de una base sql y la muestro en un Gridview mi objetivo es: el campo idproducto quiero que sea link hacia otra pagina donde se muestra todas las caracteristicas del producto, en sintesis todos los registros idproductos muestren como links, en espera de su ayuda gracias.

Leandro Tuttini dijo...

hola Cefer

podrias tener en el ItemTemplate un LinkButton al cual le asignas el Eval() con el campo del id del producto y el CommandName="Select" para asi al presionarlo se lanza el SelectedIndexChanged del gridview donde realizarias la accion

saludos

Susana dijo...

Me sirvió muchimo tu ejemplo, solo que no puede visualizar como se hace al seleccionar la fila con el mouse (o esa no era una de las formas?)

Gracias !!1

Leandro Tuttini dijo...

hola Susana

te comento que como evento que lance una accion en el servidor un al seleccionar cualquier parte de uan fila no esta contemplado

porque la fila en si mismo se renderiza como un <tr> de html, por lo tanto no tiene un evento asociado en el servidor

se usan evento de botones link o image button que si se piensan para este tipo de acciones

saludos

Javier dijo...

Muy buen artículo Leandro pero tengo un problema si en lugar de un imagebutton el control que tengo es un check (Template) dentro de la columna de la grid y quiero usar el check de la grid para saber que fila se ha seleccionado no puedo, el Template check no tiene command.

Leandro Tuttini dijo...

hola Javier

es que ene ste caso no puedes lanzar una accion de uan fila con un check, proquee sta pensado para que trabajes con multiples

o sea tendrias el check donde marcarias uno, 2, n filas del grid y luego con un boton por fuera del grid lo usarias para confirmar y procesar esas filas marcadas

pro es una accion que lanzas desde otro boton por fuera, no desde la fila concreta del gridview, porque no trabjarias con una sola, trabjarias con la seleccion de varias

usarias el FindControl() dentro de un foreach para recorrer las row del grid y ver cuales estan marcadas

saludos