lunes, 27 de febrero de 2012

[ASP.NET] Mantener información al cambiar de pagina

 

Introducción

Cuando se desarrolla pantallas de captura de datos por lo general una característica deseable implica que no se pierda los datos cargados cuando se navega a otro sitio a buscar información y se vuelve.

Lamentablemente asp.net no conserva de forma automática el estado de esta información ingresada, por esa razón seremos nosotros quienes mediante código que volquemos la info ingresada para no perderla y facilitar al usuario al operación con la aplicación.

En el ejemplo planteado se cuenta con una lista de productos, con la posibilidad de ingresa una cantidad y opciones provistas para completar la operación.

 

 

Mantener el estado de los datos ingresados

Si bien esta funcionalidad es muy similar a la implementada para mantener el estado de los check, cuenta con algunas diferencias que hay que remarcar.

En este caso se conserva algo mas de información que una simple estado de true/false, es por eso que se crea una clase para mantener los datos que son útiles.

internal class ProductInfo
{
    public int Id { get; set; }
    public int Amount { get; set; }
    public int Shipper { get; set; }
}

Es desde y hacia esta clase que se realizaran las conversiones.

El mantener la información consta de varios pasos:

  1. se recuperan del gridview solo aquellas rows en donde se ingresara una cantidad y un medio de envió. Se arma en este caso una entidad ProductInfo representativa de los datos que se quiere conservar
  2. se recupera la información previamente registrada en la session
  3. se cruzan las listas para quitar las que están en la pagina actual
  4. se ingresa la nueva información para conservar en session

 

public static void KeepProductInfo(GridView grid)
{
    //
    // se obtienen la lista de producto con informacion proporcionada por el usuario
    //
    var listProd = from item in grid.Rows.Cast<GridViewRow>()
                        let amount = ((TextBox)item.FindControl("txtAmount")).Text
                        let shipper = ((DropDownList)item.FindControl("ddlShippers")).SelectedValue
                    where !(string.IsNullOrEmpty(amount) || shipper == "0")
                    select new ProductInfo()
                    {
                        Id = Convert.ToInt32(grid.DataKeys[item.RowIndex].Value),
                        Amount= Convert.ToInt32(amount),
                        Shipper = Convert.ToInt32(shipper)
                    };

    //
    // se recupera de session la lista de seleccionados previamente
    //
    List<ProductInfo> prodInfo = HttpContext.Current.Session["ProdInfo"] as List<ProductInfo>;

    if (prodInfo == null)
        prodInfo = new List<ProductInfo>();

    //
    // se cruzan todos los ingresados en la pagina actual, con los previamente conservados 
    // en Session, devolviendo solo aquellos donde no hay coincidencia
    //
    prodInfo = (from item in prodInfo
                 join item2 in listProd
                    on item.Id equals item2.Id into g
                 where !g.Any()
                 select item).ToList();

    //
    // se agregan la actualizacion realizada por el usuario
    //
    prodInfo.AddRange(listProd);

    HttpContext.Current.Session["ProdInfo"] = prodInfo;

}

 

Por supuesto esta misma técnica puede ser usada para conservar cualquier tipo de dato de cualquier pantalla quiere se quiera evitar perder lo ingresado, se podría haber mantenido la info de textbox simple, o de un checkboxlist, combos, etc.

En este caso se uso un gridview porque es un objeto representativo de información compleja para procesar.

 

Recuperar la info de los datos conservados en session

La acción de recuperar se podría resumir en tres paso

  1. recuperar la información de session
  2. cruzar las row del gridview de la pagina actual con la lista de productos existente
  3. volcar las coincidencias en los controles textbox y dropdownlist

 

public static void RestoreProductInfo(GridView grid)
{

    List<ProductInfo> prodInfo = HttpContext.Current.Session["ProdInfo"] as List<ProductInfo>;

    if (prodInfo == null)
        return;

    //
    // se comparan los registros de la pagina del grid con los recuperados de la Session
    // los coincidentes se devuelven para ser seleccionados
    //
    var result = (from item in grid.Rows.Cast<GridViewRow>()
                  join item2 in prodInfo
                      on Convert.ToInt32(grid.DataKeys[item.RowIndex].Value) equals item2.Id into g
                  where g.Any()
                  select new
                  {
                      gridrow = item,
                      prodonfo = g.First()
                  }).ToList();

    //
    // se recorre cada item para asignar la informacion 
    //
    result.ForEach(x =>
    {
        ((TextBox)x.gridrow.FindControl("txtAmount")).Text = Convert.ToString(x.prodonfo.Amount);
        ((DropDownList)x.gridrow.FindControl("ddlShippers")).SelectedValue = Convert.ToString(x.prodonfo.Shipper);
    });
    
}

 

Uso de la funcionalidad implementada

Si bien al momento de conservar los datos ante un paginado se contaba con eventos concretos pre y post para llevar la acción de conservar o recuperar los datos, en este caso también se deberá hallar momentos equivalentes para los cuales volcar los datos.

 

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        LoadGridProducts();
        
        //
        // lusgo de cargar el grid se asigna la info que el usuario habia ingresado
        //
        ProductsManager.RestoreProductInfo(gvProducts);

    }
}

private void LoadGridProducts()
{
    gvProducts.DataSource = NorthwindData.GetAllProducts();
    gvProducts.DataBind();
}


protected void gvProducts_SelectedIndexChanging(object sender, GridViewSelectEventArgs e)
{
    //
    // se persiste la informacion ingresada por el usuario
    //
    ProductsManager.KeepProductInfo((GridView)sender);

    //
    // se recupera el producto seleccionado
    //
    int productId= Convert.ToInt32(gvProducts.DataKeys[e.NewSelectedIndex].Value);

    Response.Redirect(string.Format("ProductDetails.aspx?productId={0}", productId));
}

Tanto en la carga del formulario, como al momento de seleccionar unos de los ítems del grid es que se invocaran la funcionalidad que interactúa con el medio que conserva los datos

 

Código


El ejemplo ha sido implementado con VS2008 y hace uso de una base de datos Sql Compact

 

[C#]
[C# Skydrive]

16 comentarios:

Pierina Joplin dijo...

Hola, nuevamente yo por acá, una preguntica, sólo mantienes información de la última página visitada? o mantienes todas las páginas visitadas?
Gracias.

Leandro Tuttini dijo...

hola Pierina Joplin

puedes manter informacion de las paginas que quieras y sientas que aporta valor mantener estado, digo tampoco mantener estado de todo tendria sentido, pero donde la operacion del ir y volver es importante alli aplica

en este caso esa clase Manager solo mantiene el de esa pagian en concreto

pero si quieres mantener el de otras solo es cuestion de crearle su manager y eso es todo (aplciando esta misma tecnica)

la informacion dentro del manager puede ser tan compleja como lo necesite, solo sera cuestion de modelar la entidad que guardas en la Session

saludos

Pierina Joplin dijo...

Gracias.. Aunque no quede muy convencida.. :)

xxx dijo...

Hola, he leido tus respuestas en foro de MSDN y veo que sabes bastante, yo publique uno recientemente no hayo que hacer, agradeceria mucho tus opiniones

http://social.msdn.microsoft.com/Forums/es-ES/netfxwebes/thread/f4261091-d4e4-4a2d-8f7a-d8fc918a478e/#f4261091-d4e4-4a2d-8f7a-d8fc918a478e

Leandro Tuttini dijo...

hola xxx

he dado la respuesta en el foro, has probado lo que comento

saludos

xxx dijo...

Si Leando recien lo lei, ya conteste, gracias por el interes

Carlos Misael dijo...

Una pregunta con respecto a las variables estáticas, en un principio esa solución me pareció práctica pero el problema me resultó que cuando mas de un usuario accedia a un Formulario con un grid X que se cargaba con los datos de estáticos, se mostraban en la computadora A y B lo que estaba visualizando la computadora C o en su defecto al inicializarla por la computadora A o B la computadora C perdia su información. No se si estaré haciendo algo mal o qué. Mi solución fue utilizar variables de sesión para no usar estas variables estáticas. Salu2 desde Ecuador

Leandro Tuttini dijo...

hola Carlos Misael

efectivamente definir una variable como static implica que esta actuara como el objeto Application de asp.net, o sea sera visible para el sitio completo y todos los usuario compatiran la misma info del mismo

es por eso que si se quiere tener dato concretos por usuario se usa el objeto Session

saludos

HugoSoft dijo...

Hola Leandro, tengo una aplicación en asp.net y utilizo variables de sesión pero después de cierto tiempo que deja la pagina abierta se pierde y marca error, para recuperar la información de las variables debo enviarlas a textos y después recuperarlas (session("variable")=me.textbox1.text)?

Leandro Tuttini dijo...

hola HugoSoft

eso es comun que suceda, las session tienen un tiempo de expiracion, el valor por defecto son 20 min, si durante este tiempo no realizaste ninguna accion que implique ir al servidor, la session se pierde

deberias agregar validaciones para en caso de perder la seccion no falle la informacion que recuperas

saludos

Darkkatt dijo...

Hola Leandro, el codigo esta muy bueno, pero tengo un problema que no consigo subsanar

Tengo un area de carga de datos para el gridview, el cual posee un boton de consulta de articulos, cuando hago clic al bonton consulta de articulos me redirige a otra pagina, cuando vuelvo me trae los datos del articulo y los inserto en la grilla ingresando la cantidad y precio
El problema es que no puedo aplicar tu codigo para mantener los datos ya ingresados a la grilla

Agradeceria que me ayudes u orientes un poco en este caso

Leandro Tuttini dijo...

hola Darkkatt

no evaluaste en lugar de hacer un redirect a otra pagina para realizar la seleccion usar mejor un popup ?

[ASP.NET] PopUp Edición - Usando Jquery UI Dialog

no he implementado directo para completar campos pero la tecncia no deberia cambiar mucho

con un popup evitarias perder la edicion del grid

saludos

Ralitech - Software And Hardware dijo...

Leandro, tendrías una versión de tu código pero para VB gracias

Leandro Tuttini dijo...

hola

la verdad no lo he implementado en vb.net

aunque podrias ver de ayudarte con tool como estas

Convert c#

saludos

Encarni Serrano dijo...

Hola Leandro,
era lo que estaba buscando pero me he dado cuenta de que si una vez tengo datos en la primera y segunda página si me voy a la primera y quito algún dato al volver a esa página me vuelve a poner el dato que he quitado.
Que debería hacer?
Un saludo,

Leandro Tuttini dijo...

hola Encarni

cuando cambias entre las paginas es que se realiza la operacion de volcado de los registros marcados, podrias poner en ese evento un breakpoint y evaluar si puntualmente se esta realziando esa actualizacion, y sino es que se conservan los datos marcados previamente

verifica puntualmente donde se cruzan los datos usando linq y que esto sea efectivo
pero para esto solo es cuestion de un breakpoint y ver que resuelve los datos inspeccionado las variables

saludos