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:
- 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
- se recupera la información previamente registrada en la session
- se cruzan las listas para quitar las que están en la pagina actual
- 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
- recuperar la información de session
- cruzar las row del gridview de la pagina actual con la lista de productos existente
- 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]
|
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?
ResponderEliminarGracias.
hola Pierina Joplin
ResponderEliminarpuedes 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
Gracias.. Aunque no quede muy convencida.. :)
ResponderEliminarHola, 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
ResponderEliminarhttp://social.msdn.microsoft.com/Forums/es-ES/netfxwebes/thread/f4261091-d4e4-4a2d-8f7a-d8fc918a478e/#f4261091-d4e4-4a2d-8f7a-d8fc918a478e
hola xxx
ResponderEliminarhe dado la respuesta en el foro, has probado lo que comento
saludos
Si Leando recien lo lei, ya conteste, gracias por el interes
ResponderEliminarUna 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
ResponderEliminarhola Carlos Misael
ResponderEliminarefectivamente 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
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)?
ResponderEliminarhola HugoSoft
ResponderEliminareso 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
Hola Leandro, el codigo esta muy bueno, pero tengo un problema que no consigo subsanar
ResponderEliminarTengo 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
hola Darkkatt
ResponderEliminarno 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
Leandro, tendrías una versión de tu código pero para VB gracias
ResponderEliminarhola
ResponderEliminarla verdad no lo he implementado en vb.net
aunque podrias ver de ayudarte con tool como estas
Convert c#
saludos
Hola Leandro,
ResponderEliminarera 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,
hola Encarni
ResponderEliminarcuando 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
hola, necesito hacer una agenda en asp.net, sin BD o sea temporal. Y tengo que dirigirme simpre entre las paginas de crear, buscar y visualizar contacto, lo que no sea es como y donde declarar una application o session. En que lugar y como
ResponderEliminarhola Carolina
ResponderEliminarsi defines los datos en session estos solo seran vistos por el usuario que ingresa al sitio, cuando el usuario cierre el browser se perderan los datos
en cambio si los declaras en el Application podran ser accedidos por diferentes usuario que ingresen, porque este objeto es comun al sitio
el que mas se aproxima es el Application
saludos
Hola Leandro,
ResponderEliminarComo se haria en el caso de tener mas de un DataKeysNames??
mi caso es:
DataKeyNames="IdOferta,CódigoArtículoProveedor,WebURL"
siendo IdOferta la clave primaria...
Saludos.
hola Roberto
ResponderEliminaranaliza el final de este articulo
[ASP.NET][GridView] - Como seleccionar una fila
alli explico como lo harias
saludos
Hola Leandro, tengo una inquietud necesito mantener el contenido de una pagina que posee 4 cuadros de texto dos dropdownlist y dos checkbox como pasaría estos datos como parámetro a las funciones
ResponderEliminarKeepProductInfo y RestoreProductInfo, ya que en tu ejemplo pasas el grid como parámetro y eso te permite manipular los objetos que el mismo encapsula pero en mi caso; te agradecería me ayudes con esta inquietud desde ya un abrazo y muchos exitos
hola Omar
ResponderEliminarpodrias crear una clase que tenga las propeidades para recibir la info de estos controles
entonces creas la instancia de esa clase le asignas los valores de los textbox
esa clase podrias asignarla al objeto session para conservar los datos entre request
si la idea es asignar los valores a los controles podrias pasar por parametro la instancia de la Page
saludos
Hola Leandro, consulta para poder obtener esta misma funcionalidad, pero no para una tabla, sino para un buscador, que cuenta con textbox y select....
ResponderEliminarLograr mantener los datos aunque se pinche en un link de una tabla ?
Sldos ! espero me puedas ayudar.
hola Nicky
ResponderEliminarno se si entendi que involucra ese click en la tabla, o que relacion tiene ese textbox y select que mencionas
pero si hay un gridview podrias mantener en session los datos para no perderlos cuando se aplique una nueva busqueda
saludos
Hola Leandro, de nuevo molestando:
ResponderEliminarApliqué tu código al pie de la letra para conservar el valor del ddl; al dar click en (x) número de paginación para así al regresar al número anterior (en el que me encontraba) se quedara el valor previamente elegido en el ddl, pero no aplicó tú código.
Tienes alguna idea de cómo hacer esto?.
De antemano, Gracias
Saludos
hola Aaron
ResponderEliminara que llamas que "no aplico mi codigo" ?
si pones un breakpoint en el codigo no se detiene la ejecucion
como que estaria conservando la seleccion sin tener que implementar ningun codigo adiconal?
saludos
me refiero a que tú código ya implementado en mi aplicación no funciona al querer actualizar el gridview de nuevo, no mantiene los valores elegidos anteriormente en los dropdownlist que existen dentro del gridview, por ejemplo:
ResponderEliminarEn la primera fila tengo un ddl en el cuál selecciono un valor "FRUTAS" por ejemplo. En el segundo selecciono "LEGUMINOZAS". Al cambiar de página (dentro del mismo gridView) no me guarda esos valores.
Espero respuesta. Saludos
hola Aaron
ResponderEliminarpero si pones breakpoint e el codigo puedes evaluar que captura a deteccion del cambio de pagina y vuelca los valores seleccionados a la Session?
sino los conservas como explico en el articulo esta claro que no va a funcionar
para eso solo pon breakpoint en el codigo y valida por donde pasa la ejecucion
saludos
Creo que mi problema está en como cargo los valores del ddl, yo los cargo desde la propiedad del mismo dropdownlist que se encuentra dentro del gridView "ddl_load(object sender, eventargs e)".
ResponderEliminarEn qué difiere de la forma en la que tu lo haces?
Gracias Maestro!
hola Aaron
ResponderEliminarno uses ningun load de ningun control
usa el RowDataBound del gridview para acceder al combo que esta en esa row y asignarle los datos
saludos
Hola Leandro
ResponderEliminarcada vez se torna más complejo, disculpa por la incertidumbre y por mi insistencia.
me surgieron dos problemas;
1. Al cargar los datos con el rowDataBound el ddl de la primera fila no carga los datos, a qué se debe?... este es el código
protected void gridAcuerdos_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType != DataControlRowType.DataRow)
return;
// SE CARGA EL COMBO DE ESTADOS
DropDownList ddlAcuerdos = (DropDownList)e.Row.FindControl("ddlAcuerdos");
String str = "SELECT * FROM comboBoxAcuerdos";
SqlCommand comando = new SqlCommand(str, Conexion);
SqlDataAdapter Da = new SqlDataAdapter();
DataSet Ds = new DataSet();
try
{
Conexion.Open();
comando.ExecuteNonQuery();
Da.SelectCommand = comando;
Da.Fill(Ds, "estadoAcuerdo");
ddlAcuerdos.DataSource = Ds;
ddlAcuerdos.DataBind();
}
catch (SqlException sqlEx) // CAPTURA TODAS LAS EXCEPCIONES DE SQL
{
for (int i = 0; i < sqlEx.Errors.Count; i++)
{
errorMessages.Append("Index #" + i + "\n" +
"Message: " + sqlEx.Errors[i].Message + "\n" +
"Line Number: " + sqlEx.Errors[i].LineNumber + "\n" +
"Source: " + sqlEx.Errors[i].Source + "\n" +
"Procedure: " + sqlEx.Errors[i].Procedure + "\n");
}
Console.WriteLine(errorMessages.ToString());
}
catch (InvalidOperationException ex) // CAPTURA LA EXCEPCIÓN DE CONEXIÓN (SQLCONNECTION EXCEPTION)
{
Console.WriteLine("Excepción de conexión: " + ex.Message);
}
finally
{
Conexion.Close();
}
}
2. Cuando cambio de paginación del gridView, me invoca un error el cual es el siguiente
LA CADENA DE ENTRADA NO TIENE EL FORMATO CORRECTO.
Línea 16: let valor = ((DropDownList)item.FindControl("ddlAcuerdos")).SelectedValue
Línea 17: where !(valor == "0")
Línea 18: select new ValorInfo()
Línea 19: {
Línea 20: Id = Convert.ToInt32(grid.DataKeys[item.RowIndex].Value),
Este es el código del PageIndexChanging
protected void gridAcuerdos_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
Clases.ValorManager.KeepValorInfo((GridView)(sender));
gridAcuerdos.PageIndex = e.NewPageIndex;
//gridAcuerdos.DataSource = Session["acuerdos"];
//gridAcuerdos.DataBind();
cargarAcuerdos();
}
Gracias.
Saludos
hola Aaron
ResponderEliminar1- has puesto un breakpoint en el evento rowDatabound para validar si ingresa con la primer row y si es asi que camino toma el codigo ?
entiendo que esa primer row es un datarow por eso el if deberia pasarlo
2- en esa paete del linq que muestras no veo ningun problema
estas seguro que solo es es l linq que usas? porque alli falta definir
podrias probar de hacer mas simple el linq a ver si pasa, por ejemplo solo dejar el id sin los demas campos, y luego al contrario quitar el id he ir poniendo los otros asi para determinar cual trae el problema
saludos
excelente, funciona!!
ResponderEliminarmuchas gracias por tu paciencia y sabiduría.
Saludos
Hola Leandro,
ResponderEliminarhay una duda que me consterna demasiado, no he encontrado tema al respecto pero este es similar.
Mi duda es la siguiente: habrá alguna manera de realizar una actualización a los datos de una celda de un gridview (agregar datos(texto) a una celda) pero sin borrar los datos que ya existe en esa celda?
Te cuento que la modificación la realizo con un stored procedure que manda llamar a la función UPDATE, pero esta me cambia por completo el texto anterior por el texto nuevo y lo que deseo es agregar el texto nuevo al texto anterior.
Nota: no se deben realizar los cambios desde el mismo gridview.
Gracias.
Saludos.
hola Aaron
ResponderEliminarpero podrias usar en el select
UPDATE Tabla SET campo = campo + @param WHERE id = @id
o sea desde el procedure unes lo que tenias a lo nuevo
y si quieres despues actualizas el grid para reflejar la nueva info de esa celda
saludos
Estimado Leandro;
ResponderEliminarme gustaría saber como puedo recuperar los datos de una lista(de una clase) ejemplo:
List(Producto) LstProductos = new List(Productos)();
(creado fuera del ambito del button)
protected void Button3_Click(object sender, EventArgs e)
{
Productos prod = new Productos();
prod.NombreProd = TextBox1.Text;
prod.Categ = TextBox2.Text;
LstProductos.Add(prod);
}
...pero cuando quiero recuperar los elemntos de la lista solo muestra el ultimo
Alguna sugerencia? gracias de antemano
hola Axel
ResponderEliminares que en un entorno web no tienes estados por lo que al terminar el request la lista se destruye
deberias usar el objeto session para conservar la lista
protected void Button3_Click(object sender, EventArgs e)
{
var lista = Session["productos"] as List<Productos>;
if(lista == null){
lista = new List<Productos>();
}
var prod = new Productos(){
NombreProd = TextBox1.Text;
Categ = TextBox2.Text;
};
lista.Add(prod);
Session["productos"] = lista;
}
saludos
Estimado Leandro;
ResponderEliminarTenias toda la razón, me funcionó....
te agradezco tu tiempo y disposición para responder...
Muchas Gracias de verdad!!
Axel
hola leandro tengo un problema como le puedo hacer para que mi pagina de asp.net donde meto mis datos no se borren de la caja de texto cada vez que yo vaya a buscar un dato de otra pagina aspp.net
ResponderEliminarhola
EliminarSi vas a nevagar de una pagina atra necesitara persistir los datos de forma temporal, podrias hacer usar el objeto Session
Podrias crear una List<> de uan clase que definas (o quizas un datatable) para volcar los datos que quieres mantener, entonces navegas realizas alguna accion y al volver si detectas que la session tiene info vuelves a cargar la informacion
Es lo mismo que planteo en este mismo articulos
saludos
Hola Leandro.
ResponderEliminarTengo una pagina web en c# donde utilizó clases, con propiedades publicas y publicas staticas, donde guardo los valores que los usuarios vas ingresando y los conservo atravez de la navegación de paginas y seguir guardando información donde lo usuarios siguen ingresando información.
Me surgió la luda al ver que tú guardas tus valores en session, cosa que yo no hago. ¿Esto me puede dar problemas por concurrencia a la pagina y mezclar la información de cada objeto creado por casa usuario a la pagina, o se crean objetos independientes para cada usuario, y no dar problemas que se cruce informacion de usuarios que se encuentren en la pagina al mismo tiempo?
Agradecería mucho tu ayuda y comentarios.
Saludos
hola
EliminarEn un ambiente web no deberias usar variables definida como static ya que estas se comportan como el objeto Application o sea la informacion que asignes sera accesible a nivel del sitio web, o sea por todos los usuario, es por eso que si queres conservar los datos individuales para cada usuario de us el objeto Session
saludos
Hola Leandro.
EliminarCambien todo lo que utilizaba en variablesestaticas por el objeto Session, y una función que valida que la session siga viva, para evitar errores.
Muchas gracias. Saludos
me
ResponderEliminarHola que tal, llevo dias intentando mantener el estado de mis checkbox en un gridview estoy usando vb.net, el resultado esque al paginar mi gridview se pierde la seleccion fde mis checkbox.
Me puedes ayudar??
hola
Eliminarpero no puedes aplicar la tecnica que planteo en el articulo ? cuando paginas deberias mantener en session los valores de la paginas previas y restaurarlas cuando vuelvas a la pagina
saludos
Hola quisiera realizar el mismo proceso de guardar información en la sesión, pero en mi caso seria de la siguiente manera:
ResponderEliminarrealizo la lectura de los datos de un archivos Excel, cualquier registro del archivo que no cumpla con las especificaciones se captura y lo guardo en memoria. mi pregunta es, yo puedo realizar los mismos pasos, crear una clase con los datos a guardar y luego asignar los objetos a la variable sesión para después recuperar esa información y mostrarlos en una grilla
Muchas Gracias
Agradezco sus respuestas
Buenos días,
ResponderEliminarOjalá alguien pueda ayudarme.
Estoy teniendo problemas a la hora de que el usuario se loguea en mi página, usé Server.Transfer("Consulta.aspx") que es la página que quiero se muestre luego de que la autenticación se realice y si se habilita la otra página pero cuando deseo consultar una información en esa pagina(es un reporte, uso un sp), me vuelve a enviar a la página de login
Hola Leandro, mi duda es:
ResponderEliminarQuisiera obtener los datos que seleccioné y guardarlos en un datatable, para luego dar clic en un botón y hacer la lectura de este dataTable para mandarlo a BD.
¿Cómo puedo hacerlo?
Hola Leandro, tengo un problemón con la sesión, he visto que te has peleado el mismo problema en algún foro, aunque no he logrado solucionarlo con las referencias indicadas.
ResponderEliminarMi problema es el cruce de sesiones.
He leído que se trata de un bug de iis6 en 2003, pero yo uso Windows Servet 2016 y iis8. Framework 4.5
El problema es el siguiente hago login con web forms autentication. Registro el código de usuario y el nombre en dos variables de sesión. Hago el redirect desde login.
En la siguiente página muestro estos valores de sesión.
Me muestra los datos de otro usuario.
Cada usuario se ha logado en máquinas diferentes. Ocurre cuando atenta la concurrencia, aunque esta es mínima 10 o 15 usuarios.
Reviso el log de iis y cuando ocurre le ha cambiado el identificador de sesión al del usuario que muestra los datos. Todo usuario que se logea desde ese momento le asigna el mismo idsession. Solo ocurre en producción. No uso aspstate. Tengo marcado que no use cache. Empiezo a volverme loco.
Hola Leandro. Gracias por tu post. Tengo una consulta. ¿Cómo podría recuperar las respuestas que ha contestado un usuario de un test vocacional en caso de corte de energía eléctrica, para que al iniciar nuevamente sesión no tenga que volver a empezar? Estoy usando asp.net en c#
ResponderEliminar