domingo 8 de mayo de 2011

[ASP.NET] GridView – Edición Empleados

 

Introducción

En esta ocasión se implementara al versión web de un articulo previo:

[WinForms] Edición Empleados – Grabar imagen en base de datos

Los puntos que se trataran con detalle serán:

- selección de un fila en el gridview

- eliminar un registro del grid

- visualizar una imagen que se encuentra dentro de la base de datos en un control de Image

 

 

1 – Selección  de una fila en el GridView

Existen varias formas de lograr este objetivo, en el ejemplo del este articulo aplique solo una de ellas haciendo uso del CommandField para definir las acciones sobre el grid, para ello hice uso de la opción visual:

esto desplegara el dialogo:

es aquí donde se definen las columnas entre ellas el CommandField, al seleccionarlo mostrara las propiedades de configuración, las propiedades de la sección “Behavior” es donde uno selecciona que botones quiere visualizar, es por eso que en este caso la propiedad “ShowSelecteButton” esta en True.

Además es importante la sección “Appearance” en donde se define “ButtonType” del tipo imagen y el “SelectImageUrl”, con la url del botones que se ve en el grid.

Concluido la definición de columnas y botones de acción, se debe especificar una propiedad muy importante en el grid, se trata del “DataKeyNames”, esta debería llevar el nombre la propiedad (o columna) del origen de datos que se usara como identificación de la entidad que se edita, en este caso como son empleado, será su id, definiéndose: DataKeyNames="IdEmpleado"

Este paso es importante ya que en los eventos se podrá recuperar sobre que entidad se debe aplicar la acción.

El botón de selección lanzara el evento “SelectedIndexChanging”, es por eso que será necesario definirlo en el grid: onselectedindexchanging="gvEmpleados_SelectedIndexChanging"

mientras que en el código de la pagina:

protected void gvEmpleados_SelectedIndexChanging(object sender, GridViewSelectEventArgs e)
{
    int idempleado = Convert.ToInt32(gvEmpleados.DataKeys[e.NewSelectedIndex].Value);

    Response.Redirect(string.Format("EditarEmpleado.aspx?id={0}", idempleado));

}

Se hace uso del DataKeys para tomar el valor definido por el DataKeyNames, estas dos propiedades trabajan bien relacionadas entre ellas.

Lo último paso que queda es redireccionar a la pagina de edición.

 

2- Eliminar un registro

La operación de eliminar es muy parecida a la selección, solo cambia el comando usado para esto.

Al igual que la selección hay que configurar el CommandField habilitando la propiedad “ShowDeleteButton” en true.

Esta acción lanzara el evento “RowDeleting”, para lo cual especificamos su definición en el grid mediante: onrowdeleting="gvEmpleados_RowDeleting"

y luego en el código:

protected void gvEmpleados_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
    int idempleado = Convert.ToInt32(gvEmpleados.DataKeys[e.RowIndex].Value);

    EmpleadosDAL.Eliminar(idempleado);

    CargarGrid(); //luego de eliminar se recarga el grid
}

Aquí también se hace uso del DataKeys para recuperar el id de la entidad que lanzo la acción.

 

3- Visualizar imagen

Cuando la imagen se encuentra dentro de la base de datos es necesario usar un intermediario para poder asignarla al control Image, y se haga visible al usuario.

Además todo esto sin generar archivos temporales que permitan el acceso a la imagen.

En este caso es el handler quien nos brinda esta ayuda, si se observa el código del mismo se ve muy simple, se recupera la entidad del empleado, y a continuación si contiene una imagen asociada se poniéndola en el Response, sino hay imagen se envía una por defecto, la cual indicara que no esta disponible (líneas: 21-23).

public class HttpImageHandler : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        //
        // Se recupera la entidad empleado
        //
        int id = Convert.ToInt32(context.Request.Params["id"]);

        EmpleadoEntity empleado = EmpleadosDAL.ObtenerById(id);

        //
        // Arma el contexto que enviara la imagen en el response
        // se usa el nombre del empleado para el nombre del archivo que se envia
        //
        context.Response.Clear();
        context.Response.AddHeader("content-disposition", string.Format("attachment;filename={0}", empleado.Nombre)); 
        context.Response.ContentType = "image/jpg";

        byte[] imagenEmpleado = empleado.Imagen;
        if (empleado.Imagen == null)
            imagenEmpleado = File.ReadAllBytes(context.Server.MapPath("Imagenes/NoDisponible.jpg"));

        //
        // Se escribe en el response la imagen asociada al empleado
        //
        context.Response.BinaryWrite(imagenEmpleado);
        context.Response.End();
    }

    public bool IsReusable
    {
        get { return false; }
    }
}

Esto es tanto usado por el grid para recuperar las imágenes que lista, como así también por cualquier otro control individual que necesites mostrar la imagen del empleado.

Es por eso que en el webform “EditarEmpleado.aspx”, cuando se carga el empleado todos sus datos se asignan directo a los controles, menos el control Image que recibe una url al handler para que tome de allí la imagen que debe mostrar (línea: 18)

 

private void CargarEmpleado(int id)
{
    EmpleadoEntity empleado = EmpleadosDAL.ObtenerById(id);

    if (empleado == null)
    {
        imgEmpleado.ImageUrl = "Imagenes/NoDisponible.jpg";
        return;
    }

    lblIdEmpleado.Text = Convert.ToString(empleado.IdEmpleado);
    txtNombre.Text = empleado.Nombre;
    txtApellido.Text = empleado.Apellido;
    txtFechaNacimiento.Text = empleado.FechaNacimiento.ToShortDateString();
    
    AsignarEstudios(empleado);

    imgEmpleado.ImageUrl = string.Format("imagen.ashx?id={0}", id);
}

 

Código del artículo

El ejemplo fue desarrollado con Visual Studio 2008, y base de datos Sql Server 2008 R2 Express.

Dentro de la carpeta “script” del proyecto “DataAccess” encontrara un archivo .sql que define la estructura de datos.

 

[C#]
[VB.NET]

11 comentarios:

Marcos Carballo dijo...

Muchas gracias por el post, me sirvió mucho para lo que necesito. Te hago una consulta: si necesito cargar una imagen en un control image pero desde otra clase, o de la misma clase pero otro atributo, ¿debería crear un handler para cada imagen?
Gracias, Saludos

Marcos Carballo dijo...

tengo una clase con dos atributos imágenes y en la pantalla de edición, tengo dos controles image donde tengo que mostrar cada imagen. Probé creando un handler para cada imagen, pero a pesar de tener dos, cuando muestra las imagenes llama a un solo handler dos veces y muestra en ambos controles la misma imagen. Cómo puedo hacer indicar que en cada control image debe llamar a un handler distinto? no se si habra que modificar algo en la propiedad ImageUrl. Saludos

Marcos Carballo dijo...

ya lo pude resolver, para quien le sirva, lo que hice fue crear un solo handler y en la propiedad imageUrl del control image paso un parametro mas indicando la imagen que quiero mostrar, luego pasa dos veces por el handler y de acuerdo al parametro recibido muestra la imagen que corresponda. Algo parecido a esto:
string file = context.Request.QueryString["file"];
if (file == "logo")
{
r.WriteFile("Logo1.png");
}
else
{
r.WriteFile("Flower1.png");
}

que lo saque de la siguiente página:
http://www.dotnetperls.com/ashx

Saludos

Marcos Carballo dijo...

ahora tengo otro problema, a mi me funciona perfecto me muestra bien las imágenes, pero cuando se instala en la máquina de pruebas que tiene IIS7 como la del cliente, no muestra las imágenes. En desarrollo yo tengo todo en la misma máquina, en cambio en donde hacen las pruebas tienen por una lado la UI y en otra máquina instalan el servicio. Como te decía no me muesta las imágenes y si sobre el control image hago click derecho propiedades me sale la url de la imagen que es como esta: http://ip/VEREUI/MantenedorTablasAuxiliares/image.ashx?suministradorId=1&img=cabecera Si ingreso esta url en el navegador me sale el siguiente error: Error de servidor en la aplicación No se encuentra el recurso. El recurso que está buscando (o una de sus dependencias) se puede haber quitado, haber cambiado de nombre o no estar disponible temporalmente...
aparentemente segun pude leer algo, aunque no encontré la solución parece que hay problemas con los handlers en IIS7, quizás haya que hacer alguna configuracion diferente en el IIS7 o agregar algo mas en el web.config. Te agradecería si me puedes dar alguna pista de cual puede ser el problema. Gracias.
Saludos

Leandro Tuttini dijo...

hola Marcos

bueno imagino estas preguntas quedaron contestadas con la pregunta del foro

Mostrar imágenes desde base de datos en un control image utilizando un handler e IIS7

saludos

Axel dijo...

Hola Leandro tengo un problema con las imágenes, he estado repasando del código descargable de este post a manera de practica y si bien todos los datos se muestran correctamente ,cuando se carga la pagina ListaEmpleados.aspx el campo de imagen se muestra con el típico icono de imagen no disponible(Las imágenes si esta correctamente guardadas porque en la versión de escritorio se las visualiza correctamente) Alguna idea del porque esto esto esta pasando? alguna configuración extra para el HttpImageHandler.vb??.
Gracias y saludos

Leandro Tuttini dijo...

hola Axel

en que entorno sucede estos, es en desarrollo o cuando lo llevas a produccion en el server ?

si es durante desarrollo, imagino que has intentado poner un breakpoint en el handler y ver que pase por alli para poner en el Response la imagen que quieres enviar

veo que marcar temas de configuracion, recuerda que el handler debe estar en el web.config para poder ser reconocido, validalo porque alli lo menciono


saludos

Axel dijo...

Si le puse un breakpoint, pero no entraba y me parecía raro porque ya anteriormente había hecho algo similar pero con un Generic Handler(.ashx) y con ese tipo de archivo nunca había tenido que agregar nada al web.config y si, también vi que habían preguntas similares a la mía sobre problemas con las imágenes, pero no le preste atención porque mencionaban IIS7 y yo tengo la versión 6,grave error :( ,bueno ya agregue la linea y ahora funciona correctamente :D . Supongo que no hay diferencia entre usar un handler de extensión .ashx frente a un .vb, o si??
Gracias y Saludos

Leandro Tuttini dijo...

hola Axel

Supongo que no hay diferencia entre usar un handler de extensión .ashx frente a un .vb, o si?

pero vb es la extension que usas vb.net para identificar sus archivos de clase, no creo que sea conveniente usar esa extension

si lo analizas la extension .ashx es un invento para mapear una algo identificable con una clase que implementa IHttpHandler, pero es solo eso, se podria usar cualquier extension siempre y cuando se defina en el web.config

pero por las dudas trata de no usar las que ya estan de antemano definidas para otras cosas como es el caso de .vb usando por vb.net

saludos

Jemmy dijo...

Hola leandro soy un fiel seguidor de tus post, quiero que me ayudes con un problema que tengo el cual consiste en pasar datos de un grid a otro( si ya vi tu post), el problema es k no me sale, quisiera que manejaras tus ejemplos con bases de datos como postgres o sql server, por favor me urge un ejemplo...
Mi correo es eggman_86@hotmail.com
Gracias espero tener una direccion para estar en contacto contigo. :)

Leandro Tuttini dijo...

hola Jemmy

pero habias visto este ejemplo

[ASP.NET] – Pasar valores entre dos GridView

porque me parecio raro que hicieras esta pregunta en este articulo cuando el otro es adapta mas a lo que comentas

ademas que use una db o no deberia seri indistinto para apsar los items porque la idea es realziar esta oiperacion en la presentacion

luego si conformas y quieres registras los items que se han seleccionado solo es cuestion de recorrerlos y realziar las operaciones de INSERT en la table de la db

saludos