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

 pantalla



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:


 image


esto desplegara el dialogo:


 image


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.
Concluida 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]

[jQuery] RadioButton y CheckBox

 

Introducción

Después del artículo donde se analizo la forma de trabajar con controles de lista como ser los combos y listbox

[jQuery] Trabajo con ListBox y Combos

seguiremos con otro grupo de controles igual de importantes: Radio Buttons y Checkbox.

Listado de temas

  1. RadioButton
    1. Recuperar ítem Seleccionado
    2. Asignar Selección
    3. RadioButtonList
  2. CheckBox
    1. Recuperar ítem Seleccionado
    2. Asignar Selección
    3. CheckBoxList

 

1- RadioButton

1.1 – Recuperar ítem Seleccionado

En las siguientes líneas se observara algunas de las formas posibles en que se puede recuperar el ítem seleccionado en un radio button.

 

function btnEj1SeleccionUsandoClass_OnClick() {

    var valor = $('.Ej1radio:checked').val()

    $('#Ej1Resultado').html(valor);
}

function btnEj1SeleccionUsandoName_OnClick() {

    var valor = $("input[name='Ej1radio']:checked").val()

    $('#Ej1Resultado').html(valor);
}

function btnEj1SeleccionUsandoTabla_OnClick() {

    var valor = $("#Ej1Table :radio:checked").val()

    $('#Ej1Resultado').html(valor);
}

Básicamente en todas se hace uso del selector :checked para tomar los radio marcados por el usuario, al saber que solo uno puede seleccionarse, se recupera el valor mediante el método val()

1- se usa una clase asignada a los distintos radio button, por el uso del punto, este es el selector de clase de jquery

2- se selecciona por medio de atributo name, todos los radio deben tener el mismo

3- se selecciona la tabla que contiene los controles , luego los radio (mediante :radio), hay que mencionar que si en la misma tabla existe otro grupo de radio button este tipo de selección no podría ser aplicado, porque tomaría todos los radio sin discriminar cada agrupación

1.2 – Asignar selección

La asignación de un valor especifico a los radio se reduce a cambiar el atributo checked.

function btnEj2SeleccionarConTabla_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    $("#Ej2Table :radio[value='" + valor + "']").attr('checked', true);

}


function btnEj2SeleccionarPorName_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;
        
    $(":radio[name='Ej2radio'][value='" + valor + "']").attr('checked', true);

}

En ambos caso se asigna el atributo “checked” a true para que este se desmarque, como los radio trabajaban en grupo no hace falta desmarcar al resto, ya que esto se hace automáticamente.

1- se selecciona la tabla que contiene el radio y se usa como filtro el valor ingresado en el textbox

2- se usa el nombre que define al grupo de radio buttons, luego sobre estos filtrar por el valor

También existen otras formas de seleccionar un ítem:

function btnEj2SeleccionarAtributoJavascript_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    var option = $(":radio[name='Ej2radio'][value='" + valor + "']");

    if (option.length > 0)
        option[0].checked = true;

}

function btnEj2SeleccionarConForEach_OnClick() {
    
    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    $.each($("#Ej2Table :radio"), function() {

        if (this.value == valor) {
            this.checked = true;
        }

    });

}

1- se busca el option que coincide, pero la acción de checkear se logra por medio de la propiedad provista por javascript. El usar el ítem cero [0], no es porque la selección devuelve varios resultados en la búsqueda en un array, sino que se esta tomando el control javascript de la selección de jquery.

2- aquí la búsqueda se realiza mediante un loop por todos los radio, comparando su valor con el buscado, el que coincida será marcado

1.3 – RadioButtonList

En esta sección se hará uso de control propuesto por asp.net para representar un conjunto de radios.

Si se analiza con el “IE Developer Tools”, al cual se accede presionado F12, se podrá inspeccionar el html generado por el control de lista de radio buttons

Como se observa la opción esta compuesta por el input común de html, pero la descripción esta dentro de un label

function btnEj3SeleccionUsandoName_OnClick() {

    var option = $(":radio[name='rdlEj3']:checked");
    var texto = $('label', option.parent());

    var msg = 'texto: {0}, valor: {1}'.format(texto.html(), option.val());

    $('#Ej3Resultado').html(msg);
}

Es por eso que luego de tomar la option seleccionado se usa el parent() para subir un nivel, ahora estaremos posicionado en el tag <td>, y dentro de este se recupera el label, de esta forma se obtendrá la descripción del option marcado.

Algo interesante aquí es que en la línea

$('label', option.parent())

se esta usando un selector de un selector, o sea se buscara solo el label que este dentro de ese tag <td> y no en todo el sitio, es por eso que se separa por coma, a la izquierda iría la selección del ámbito donde aplica el selector de la derecha.

2- CheckBox

2.1 - Recuperar ítem Seleccionado

En la selección del checkbox se necesita algo mas de código, ya que pueden ser varios los ítems marcados.

En todos los ejemplos se recorren los checks elegidos y se vuelca a una array para mostrar el resultado en pantalla, aquí se aplica la misma técnica que en el artículo previo, cuando se analizo el ListBox.

function btnEj1SeleccionUsandoClass_OnClick() {

    var list = new Array();

    $.each($('.Ej1check:checked'), function() {

        var msg = 'valor: {0}'.format($(this).val());
        list.push(msg);

    });

    $('#Ej1Resultado').html(list.join('
'));
}

function btnEj1SeleccionUsandoName_OnClick() {
    
    var list = new Array();

    $.each($("input[name='Ej1check']:checked"), function() {

        var msg = 'valor: {0}'.format($(this).val());
        list.push(msg);

    });

    $('#Ej1Resultado').html(list.join('
'));
    
}

function btnEj1SeleccionUsandoTabla_OnClick() {

    var list = new Array();

    $.each($("#Ej1Table :checkbox:checked"), function() {

        var msg = 'valor: {0}'.format($(this).val());
        list.push(msg);

    });

    $('#Ej1Resultado').html(list.join('
'));
    
}

1- se hace uso de la clase asignada a los ckeck para determinar cuales fueron marcados, al igual que los radio se usa el punto de jquery como selector

2- el mismo nombre es usado en cada check que forma parte del grupo, este es usando este como selector, el name es un atributo por eso es que se define entre []

3- se selecciona la tabla que contiene los checks, recorriendo los seleccionados

2.2 - Asignar Selección

Aquí también hay varias formas de lograrlo al igual que los radio, pero a diferencia del control anterior si es necesario un paso previo que limpie la selección previa, es por eso que se hace uso del metodo attr() que asigna el atributo checked en false

$("#Ej2Table :checkbox").attr('checked', false);

puede variar la forma en que se aplica la selección de jquery, pero la idea es obtener todos los checks y de un golpe desmarcarlos.

En estos ejemplo se puede ingresar en el TextBox varios valores separados por coma, es por eso que se recorre cada numero ingresado para tomar el check que mapea con este valor y marcarlo. Se logra este objetivo por medio del $.each y el split() de la cadena de valores ingresados.

 

function btnEj2SeleccionarConTabla_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    $("#Ej2Table :checkbox").attr('checked', false);
    
    $.each(valor.split(','), function() {
    
        $("#Ej2Table :checkbox[value='" + this + "']").attr('checked', true);

    });

}


function btnEj2SeleccionarPorName_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    $(":checkbox[name='Ej2check']").attr('checked', false);

    $.each(valor.split(','), function() {

        $(":checkbox[name='Ej2check'][value='" + this + "']").attr('checked', true);

    });

}

1- se hace uso de la tabla para tomar los check que están contenidos

2- se recuperan los check por el atributo name asignado al grupo

 

function btnEj2SeleccionarAtributoJavascript_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    $(":checkbox[name='Ej2check']").attr('checked', false);

    $.each(valor.split(','), function() {

        var option = $(":checkbox[name='Ej2check'][value='" + this + "']");
        
        if (option.length > 0)
            option[0].checked = true;
    });

}

3- se hace uso de la propiedad checked de javascript para marcar el control, aquí la selección recupera el check concreto, pero luego con el uso de [0] se toma el control puro en javasscript que contiene esa propiedad checked

Remarco que la propiedad checked no es parte de jquery, este usa el attr() para cambiar el valor, solo javascript posee esta propiedad, por eso el uso del [0] en el resultado del selector de jquery

 

function btnEj2SeleccionarConForEach_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;
    
    $(":checkbox[name='Ej2check']").attr('checked', false);
    
    
    $.each($("#Ej2Table :checkbox"), function() {

        var check = this;
        
        $.each(valor.split(','), function() {

            if (check.value == this)
                check.checked = true;

        });

    });

}

4- se aplica la misma técnica del punto 3, pero se realiza un doblo loop, primero por cada check en la tabla y luego por los valores ingresados. No digo que esta sea la forma mas optima de implementarlo, pero me pareció interesante mostrarlo para conocer como unir dos ciclos.

 

function btnEj2SeleccionarUniendoValores_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    $(":checkbox[name='Ej2check']").attr('checked', false);

    var valuesList = Array();

    $.each(valor.split(','), function() {

        var value = "[value='{0}']".format(this);
        valuesList.push(value);

    });

    $(":checkbox[name='Ej2check']").filter(valuesList.join(',')).attr('checked', true);

}

5- esta ultima técnica de selección es bastante particular ya que arma un array de filtros que es ejecutado mediante el método filter() de jquery sobre la selección de todos los checks. Es necesario marcar que cada ítem del filtro deberá ser separado por comas.

2.3- CheckBoxList

Al igual que con el RadioButtonList, es una buena idea inspeccionar el html resultante del render

Algo interesante que se puede observar es que el control rendiza una tabla de nombre “rdlEj3” que podría ser usada para seleccionar los check contenidos en esta.

function btnEj3SeleccionUsandoName_OnClick() {
   
    var options = $("#rdlEj3 :checkbox:checked");

    var list = new Array();

    $.each(options, function() {

        var option = $(this);
        var valor = $(this).parent().attr('hiddenValue');
        var texto = $('label', option.parent());

        var msg = 'texto: {0}, valor: {1}'.format(texto.html(), valor);
        list.push(msg);

    });

    $('#Ej3Resultado').html(list.join('
'));
}

En este caso se toma los check dentro de la tabla que asp.net crea para contener estos controles, tomando de esta solo los tildados.

Algo que debe marcarse es que el CheckBoxList no ingresa el valor de cada ítem, es por eso que en el código .net en el evento Page_Load cuando se asignan los ítems, se pusieron unas líneas que agregan el valor del ítem

foreach (ListItem item in rdlEj3.Items)
{
    item.Attributes["hiddenValue"] = item.Value; 
}

Esto se rendizan en el html dentro de un tag <span>, es por eso que en las líneas 9 al 11 se hace uso del parent() para subir un elemento al seleccionado y recuperar esta información.

El control base que provee asp.net solo crea el atributo value=”on” como puede verse en la imagen, el atributo “hiddenValue” es creado al en el loop de cada ítem luego de cargar la lista.

 

Ejemplo de código