Introducción
Suelen darse los escenarios en donde se necesite editar distintas entidades pero haciendo uso de un único control gridview.
Una respuesta rápida a este problema seria hacer uso de la propiedad AutoGenerateColumns en true, para que los datos que se le proporciona al control defina las columnas que debe mostrar, lo malo de esta opción es que se pierde control sobre la grilla.
Otra alternativa interesante podría ser el uso de la clase BoundField con esta seria posible definir columnas en tiempo de ejecución, si bien podría ser la solución en la mayoría de los caso, esta no permite un control total del témplate que se debe usar en al edición de las columnas.
La solución definitiva al problema esta en la implementación de témplates de columnas, estas clases especializadas contendrán el código del témplate que define, para que esto se posible se necesitara implementar la interfaz ITemplate
El modelo del ejemplo de código planteado hace referencia a dos listados, uno de notebooks y otro de televisores, ambos con distintas columnas por mostrar, pero haciendo uso de un solo control de grilla y la definición de las columnas de forma explicita en runtime.
Uso del BoundField
La definición de las columnas mediante esta clase podrá apreciarse en el formulario de nombre “GridViewBoundField.aspx”
public partial class GridViewBoundField : System.Web.UI.Page { protected void Page_Init(object sender, EventArgs e) { DefinirColumnasNotebook(); } protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { GridView1.DataSource = DataAccess.ObtenerListaNotebook(); GridView1.DataBind(); } } private void DefinirColumnasNotebook() { // // Se define el campo dentro de la grilla, // para poder identificar cada item // GridView1.DataKeyNames = new string[] { "Id" }; GridView1.Columns.Clear(); BoundField tempDesc = new BoundField(); tempDesc.HeaderText = "Descripcion Producto"; tempDesc.DataField = "Descripcion"; GridView1.Columns.Add(tempDesc); BoundField tempPrecio = new BoundField(); tempPrecio.HeaderText = "Precio"; tempPrecio.DataField = "Precio"; GridView1.Columns.Add(tempPrecio); } }
Se notara en el código que las columnas son definidas en el evento Page_Init, mientras que los datos son cargadas en el Page_Load
Esto es porque la definición de las columnas al ser dinámicas se deberán crear cada vez que se realice un postback, mientras que los datos pueden volver a bindear a la grilla, o no, eso dependerá de la funcionalidad que se quiera lograr
Definición de ITemplate
La definición de las columnas por medio de la creación de templetes de columnas, podrá apreciarse en el formulario de nombre “GridViewITemplate.aspx”.
Para poder hacer uso de template de columnas en el control GridView, será necesario la implementación de a interfaz ITemplate, a continuación se vera el código de estas clases:
public class GridViewHeaderTemplate : ITemplate { string text; public GridViewHeaderTemplate(string text) { this.text = text; } public void InstantiateIn(System.Web.UI.Control container) { Literal lc = new Literal(); lc.Text = text; container.Controls.Add(lc); } } public class GridViewEditTemplate : ITemplate { private string columnName; public GridViewEditTemplate(string columnName) { this.columnName = columnName; } public void InstantiateIn(System.Web.UI.Control container) { TextBox tb = new TextBox(); tb.ID = string.Format("txt{0}", columnName); tb.EnableViewState = false; tb.DataBinding += new EventHandler(tb_DataBinding); container.Controls.Add(tb); } void tb_DataBinding(object sender, EventArgs e) { TextBox t = (TextBox)sender; GridViewRow row = (GridViewRow)t.NamingContainer; string RawValue = DataBinder.Eval(row.DataItem, columnName).ToString(); t.Text = RawValue; } } public class GridViewItemTemplate : ITemplate { private string columnName; public GridViewItemTemplate(string columnName) { this.columnName = columnName; } public void InstantiateIn(System.Web.UI.Control container) { Literal lc = new Literal(); lc.DataBinding += new EventHandler(lc_DataBinding); container.Controls.Add(lc); } void lc_DataBinding(object sender, EventArgs e) { Literal l = (Literal)sender; GridViewRow row = (GridViewRow)l.NamingContainer; string RawValue = DataBinder.Eval(row.DataItem, columnName).ToString(); l.Text = RawValue; } } public class GridViewItemCheckTemplate : ITemplate { private string columnName; public GridViewItemCheckTemplate(string columnName) { this.columnName = columnName; } public bool CanEdit { get; set; } public void InstantiateIn(System.Web.UI.Control container) { CheckBox check = new CheckBox(); check.ID = string.Format("chk{0}", columnName); check.Enabled = this.CanEdit; check.DataBinding += new EventHandler(check_DataBinding); container.Controls.Add(check); } void check_DataBinding(object sender, EventArgs e) { CheckBox check = (CheckBox)sender; GridViewRow row = (GridViewRow)check.NamingContainer; string value = DataBinder.Eval(row.DataItem, columnName).ToString(); check.Checked = bool.Parse(value); } }
Cada una representa un témplate de visualización y edición dentro del Gridview.
El método principal que debe implementarse es InstantiateIn(), dentro de este se definirá el o los control que conformen el témplate de columna para el estado especifico.
Algo que seguramente llamara la atención es el uso del evento DataBinding, el cual es usada para tomar los datos al momento de bindear cada fila de la grilla, este evento será ejecutado tantas veces como filas tenga.
Estas clases serán usadas para definir cada témplate de columna:
private void DefinirColumnasNotebook() { // // Se define el campo dentro de la grilla, // para poder identificar cada item // GridView1.DataKeyNames = new string[] { "Id" }; GridView1.Columns.Clear(); // // Columna Descripcion // TemplateField tempDesc = new TemplateField(); tempDesc.HeaderTemplate = new GridViewHeaderTemplate("Descripcion Producto"); tempDesc.ItemTemplate = new GridViewItemTemplate("Descripcion"); tempDesc.EditItemTemplate = new GridViewEditTemplate("Descripcion"); GridView1.Columns.Add(tempDesc); // // Columna Precio // TemplateField tempPrecio = new TemplateField(); tempPrecio.HeaderTemplate = new GridViewHeaderTemplate("Precio"); tempPrecio.ItemTemplate = new GridViewItemTemplate("Precio"); tempPrecio.EditItemTemplate = new GridViewEditTemplate("Precio"); GridView1.Columns.Add(tempPrecio); } private void DefinirColumnasTelevisores() { GridView1.DataKeyNames = new string[] { "Id" }; GridView1.Columns.Clear(); // // Columna Descripcion // TemplateField tempDesc = new TemplateField(); tempDesc.HeaderTemplate = new GridViewHeaderTemplate("Descripcion Televidor"); tempDesc.ItemTemplate = new GridViewItemTemplate("Descripcion"); tempDesc.EditItemTemplate = new GridViewEditTemplate("Descripcion"); GridView1.Columns.Add(tempDesc); // // Columna PrecioUnitario // TemplateField tempPrecio = new TemplateField(); tempPrecio.HeaderTemplate = new GridViewHeaderTemplate("Precio Unitario"); tempPrecio.ItemTemplate = new GridViewItemTemplate("PrecioUnitario"); tempPrecio.EditItemTemplate = new GridViewEditTemplate("PrecioUnitario"); GridView1.Columns.Add(tempPrecio); // // Columna EsPlasma // TemplateField tempEsPlasma = new TemplateField(); tempEsPlasma.HeaderTemplate = new GridViewHeaderTemplate("Plasma"); GridViewItemCheckTemplate esPlasmaItem = new GridViewItemCheckTemplate("EsPlasma"); tempEsPlasma.ItemTemplate = esPlasmaItem; GridViewItemCheckTemplate esPlasmaEdit = new GridViewItemCheckTemplate("EsPlasma"); esPlasmaEdit.CanEdit = true; tempEsPlasma.EditItemTemplate = esPlasmaEdit; GridView1.Columns.Add(tempEsPlasma); }
Se define tanto el témplate del Ítem, como el de edición y encabezado, usando para ello el témplate que corresponda, se debe tener presente que también el tipo de dato a mostrar influye en la decisión de que témplate utilizar, un ejemplo muy claro lo representa el checkbox que marca si el televisor es de plasma o no, representado por un témplate que justamente dibuja un check en la celda.
También hay que comentar que no hay una forma única de crear las clases de témplate, estas podrían tomar la info mediante propiedades o pasarlas en el constructor. Un ejemplo de esto es la clase “GridViewItemCheckTemplate” la cual asigna el nombre del campo al cual vincula los datos, pero si debe permitir la edición o no, es asignada mediante una propiedad, tomando un valor por defecto en caso de no asignar valor.
La edición de un registro en la grilla implica todo un tema:
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e) { GridView1.EditIndex = e.NewEditIndex; DataBindGrid(); } protected void GridView1_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e) { GridView1.EditIndex = -1; DataBindGrid(); } protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e) { int Id = Convert.ToInt32(GridView1.DataKeys[e.RowIndex].Value); GridViewRow row = GridView1.Rows[e.RowIndex]; if (Session["datos"] is List<Notebook>) { Notebook notebookActualizada = (from item in (List<Notebook>)Session["datos"] where item.Id == Id select item).FirstOrDefault(); TextBox txtDescripcion = row.FindControl("txtDescripcion") as TextBox; notebookActualizada.Descripcion = Convert.ToString(txtDescripcion.Text); TextBox txtPrecio = row.FindControl("txtPrecio") as TextBox; notebookActualizada.Precio = Convert.ToInt32(txtPrecio.Text); } else if (Session["datos"] is List<Televisor>) { Televisor televisorActualizado = (from item in (List<Televisor>)Session["datos"] where item.Id == Id select item).FirstOrDefault(); TextBox txtDescripcion = row.FindControl("txtDescripcion") as TextBox; televisorActualizado.Descripcion = Convert.ToString(txtDescripcion.Text); TextBox txtPrecio = row.FindControl("txtPrecioUnitario") as TextBox; televisorActualizado.PrecioUnitario = Convert.ToInt32(txtPrecio.Text); CheckBox chkEsPlasma = row.FindControl("chkEsPlasma") as CheckBox; televisorActualizado.EsPlasma = chkEsPlasma.Checked; } GridView1.EditIndex = -1; DataBindGrid(); }
Mediante los evento RowEditing y RowCancelingEdit, se controla que la fila este o no en estado de edición, esto indica a la grilla cuando debe cambiar el témplate de edición que se ha definido.
El evento RowUpdating actuara cuando se acepta la edición, es en este momento donde controla que tipo de lista se esta visualizando, como primer paso se localiza la entidad dentro de la colección que se había usado para bindear la grilla, para esta tarea se hizo uso de Linq.
Luego se toma la información de los controles que genero cada template, hay que remarcar en este punto que los template usan internamente el agregado de un prefijo con respecto al tipo de control que agregan, agregando este al nombre de la columna que se le asigno, por ejemplo:
tb.ID = string.Format("txt{0}", columnName);
Esta línea agrega el prefijo “txt” al nombre del campo, es por esto que luego al buscar el control se uso
TextBox txtDescripcion = row.FindControl("txtDescripcion") as TextBox;
En donde “Descripcion” es el nombre del campo, y “txt” el prefijo.
Al igual que se hizo con el BoundField, en este caso la definición de las columnas se realiza en el Page_Init
protected void Page_Init(object sender, EventArgs e) { if (Session["datos"] == null || Session["datos"] is List<Notebook>) { DefinirColumnasNotebook(); } else if (Session["datos"] is List<Televisor>) { DefinirColumnasTelevisores(); } } protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { Session["datos"] = DataAccess.ObtenerListaNotebook(); DataBindGrid(); } } private void DataBindGrid() { GridView1.DataSource = Session["datos"]; GridView1.DataBind(); }
Hay un método adicional que por ahí no este tan claro, DataBindGrid(), este método simplemente toma la info de session y bindea la grilla, este cache de información en session me pareció importante ya que por cada accion que se realiza la grilla debe ser bindeada a los datos, lo cual podría producir una sobrecarga de comunicación si en todo momento debe ir controla la db para buscar la información.
Ejemplos de Código
El ejemplo fue confeccionado con Visual Studio 2008.
[C#] |
[VB.NET] |
Hola Leandro
ResponderEliminarUna consulta.
Como puedo llamar a otro formulario haciendo click en una celda del datagridview de otro formulario.
Me ha salido con una columna del tipo
DataGridViewButtonColumn
en visual .net 2008
algo asi
Private Sub DataGridView1_CellContentClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
If e.ColumnIndex = 0 Then
Dim formulario As New Form2()
formulario.ShowDialog()
End If
End Sub
pero no me sale cuando la columna es del tipo
DataGridViewTextBoxColumn
que codigo podria implementar
para conseguir el mismo efecto
Muchas Gracias
Saludos
Leandro masomenos resolvi este tema con un artículo tuyo.
ResponderEliminarPara complementar , quería saber como puedo hacer para truncar al form.Osea de un Form1
llamo al Form2, pero no quisiera crear varias instancias hasta que seleccione algo del Form2 para pintarlo en el Form1.
Me guie de este ejemplo tuyo
C# – DataGridView – Parte 3 – Pasaje de información entre grillas en distintos formulario.
Agradezco de antemano tu respuesta.
Saludos
hola Augusto
ResponderEliminarQue bueno que los articulos son de utilidad.
Bien con respecto al planteo me surgen algunas dudas, no veo la relacion entre crear instancias y pintar en un formulario.
Las acciones no me quedan claras, basicamente lo que pasas es informacion de un form al otro, y las instancias no son varias, son siempre las mismas que se pasan de in form al otro para poder comunicarse
Si la pregunta es algo compleja de explicar, te aconsejaria que la realices en los foros de MSDN:
Foro C#
Alli participo activamente, sino soy yo quien la responde seguro habra mucho colaboradores con ganas de ayudar.
saludos
Buenos dias Leandro. No he tenido mucho tiempo de revisar todo el material que has colocado en este sitio razón por la que te planteo esta pregunta: ¿puedo crear dataadapters asi: select * from productos where IdePro = @IdePro
ResponderEliminarusando el asistente?
Uso vs2010 express
hola Marlon
ResponderEliminarAunque no lo has mencionado imagino que por asitente te refieres al que provee la creacion de DataSet tipados.
O sea cuando concluye el asistente obtiene un archivo de extension .xsd, en donde se definen datatable con campos y puede usar los TablaAdapter de cada datatable.
Si es asi podrias comentarte que si puedes hacer esto que mencionas, podrias extrender la funcionalidad, revisa este link:
Building a DAL using Strongly Typed TableAdapters and DataTables in VS 2005 and ASP.NET 2.0
Alli veras como agregar nuevos metodos con parametros en tu consulta para extender la funcionalidad.
De esta forma podrias crear un metodo que toma como parametro IdePro, que usaras luego en la query del TableAdapter.
Bueno espero esto sea de utilidad
saludos
Buenas noches Leandro.
ResponderEliminarMi planteamiento: resulta que tengo un proyecto en donde si coloco un picturebox y le asigno una imagen no me muestra nada. tuve problemas con un módulo y observé que me falta el archivo Resources.Designer.cs. Estoy seguro que este es el problema. Ahora, no se como recuperarlo o reconstruirlo. Gracias por adelantado...
hola MarlonVillamizar
ResponderEliminarNo has probado regenerando el archivo de recurso, como explica este link
Missing auto-generated Resources.Designer.cs file
Veras que este recursos puede encontrarse oculto en la carpeta "Properties" del proyecto:
imagen
saludos
Hola Leandro.
ResponderEliminarTengo una duda que si bien es algo que parece superficial me gustaría si hay alguna forma practica de resolverla.
Resulta que no he querido usar AutoGenerateEditButton="True" y me he creado mis Clases para poder usar ImageButtons: Public Class GridViewItemCommandTemplate(aqui agregue un ImageButton para Edit y otro para Delete) y en GridViewEditCommandTemplate los ImageButtons para Update y Cancel, a pesar de que todo me funciona OK(auque tal vez no sea la mas adecuada ), me gustaria saber si hay alguna manera de InstantiateIn en ambas clases, crear/agregar algo en medio de ambos imagebuttons de manera que haya espacios en blanco entre los botones(tanto entre edit y delete como entre Update y cancel) porque quedan muy pegados.
ya ves porque te digo q es algo q parece muy superficial, pero me gustaría saber si hay una forma practica de lograrlo antes de intentar salidas no muy practicas. :D
Saludos y gracias de antemano
hola Axel
ResponderEliminarno se si entendi del todo el planteo, pero si estas diseñando tu mismo el template podrias agregar html que le de formato
por ejemplo podrias agregar un para poner espacios, pero como se que es por codigo esto lo haces con el HtmlGenericControl
aunqru creo que con el LiteralControl tambien funciona
entonces creas una instancia
LiteralControl espacio = new LiteralControl(" ");
contenedor.Controls.Add(espacio);
es mas podrias hasta usar tablas de html si lo necesitas, recuerda que esta el HtmlTable como clase y puedes desde codigo .net armar html con estas
saludos
Buenas Leandro, tengo una duda sobre Linq, si bien es cierto la reducción de código es bastante notoria con Linq, que me podrías decir del rendimiento, es este mayor, menor o igual??
ResponderEliminarSaludos y gracias
hola Edalo
ResponderEliminarte cuento que la situacion varia segun que buscas si sitieen uan lista con quizas 100 items si aplcias linq puedo asegurater que elr endimiento anda perfecto
ahora si hablamos de imaginemos 10000 items bueno aqui hay que tenee algo asm de cuidado, primero porque son items en memoria, y depsues porque si apcais alguna operacion compleja como ser la union con otra lista, o agrupados, etc
puedes algun problema
pero yo lo he usado con listas de 200000 items y la verdad sin problemas
algio igual que no has mencionado es a que linq haces referencia porque yo apunto a alinq basico, no a linq to sql o a linq to entities
aunque igual estos son muy bueno tambien para mapear las entidades a la tabla de tu db
saludos
Hola Leandro, tengo una duda, tengo un gridview con 3 columnas, una de ellas tiene un LABEL, la segunda tiene un Combobox y la ultima un textbox, quisiera poder llenar solamente la primera columna donde estan los label, pasandole una lista de una clase materia: list();
ResponderEliminartengo este codigo:
public void Inicio()
{
int i;
GridViewRow row;
Label chequeado = new Label();
for (i = 0; i < GridView1.Rows.Count; i++)
{
row = GridView1.Rows[i];
if (row.RowType == DataControlRowType.DataRow)
{
chequeado = (Label)row.FindControl("LabelMateria");
chequeado.Text ="Calculo II";
row.FindControl("LabelMateria").Controls.Add(chequeado);
GridView1.Controls.Add(row);
;
}
}
}
creo que la linea que dice GridView1.Controls.Add(row); esta mala, como le asigno propiamente a esa columna del Gridview la lista de materias, de antemano muchas gracias!
hola Kleyvert
ResponderEliminarun primero punto, para que haces esto:
Label chequeado = new Label();
si despues haces:
chequeado = (Label)row.FindControl("LabelMateria");
porque directamente no haces:
Label chequeado = (Label)row.FindControl("LabelMateria");
o sea defines y asignas directamente
ademas estas lineas:
row.FindControl("LabelMateria").Controls.Add(chequeado);
GridView1.Controls.Add(row);
no hacen falta para nada
si has usado el FindControl y localizado el label en la row y cambias su valor, con eso alcanza
saludos
Hola Leandro,
ResponderEliminarMuchas gracias por la entrada.
Me sirvió mucho para un gridview dinámico que estoy haciendo.
Ahora quería añadirle al checkbox dinámico la propiedad CommandName para controlar qué checkboxes se marcan y actualizarlos en la BD, pero no encuentro la forma.
Muchas Gracias,
Saludos
hola Ivan
ResponderEliminarpero en el articulo ya se trata el tema de crear un template dinamico con checkbox
seria similar a la clase GridViewItemCheckTemplate
quizas en tu caso el tema del CanEdit no lo tendrias
pero la tecnica seria igual
saludos
Hola Leandro,
ResponderEliminarMuchas gracias por tu atención.
Me ayudó mucho tu sugerencia.
Al final usé tu ejemplo para generar el gridview dinámico pero para el checkbox utilicé la idea de "http://aspadvice.com/blogs/joteke/archive/2006/10/13/Command_2D00_capable-CheckBox-with-GridView.aspx"
Saludos
Hola Leandro, una consulta, las clases me funcionaron bie, muchas gracias; pero al momento de exportar los datos a excel me muestra una tabla vacia. ¿Como puedo solucionarlo y a que se debe?
ResponderEliminarDe antemano muchas gracias.
hola Omar
ResponderEliminarpero al momento de exportar estas recreando la estructura del gridview?
porque recuerda para exportar seguro lance el render con lo cual debes volver a asignar estas columnas que creas desde codigo
saludos
Hola Leandro, muchas gracias por la ayuda, eso es lo que me estaba faltando ahora ya se muestran los datos cuando exporto la tabla a excel.
ResponderEliminarSaludos
Gracias!!! muy buen post!
ResponderEliminarExcelente post, quería bajar los archivos pero no están disponibles, vuelve a subirlo por favor.
ResponderEliminarhola marco
ResponderEliminaryo pude descargarlo sin problemas
saludos
hola Leandro esta bueno el ejemplo yo estoy trabajando algo similar en c# pero me gustaria si me pudieras ayudar, como recuperar los valores que son escritos en los textbox dinamicos creados dentro del Gridview, ya ke cuando los creo fuera del grid , puedo recuperar pero los ke estan dentro del grid no puedo saber los valores ke son escritos... gracias
ResponderEliminarhola Elmer
ResponderEliminaren que evento defines las columnas del gridview? porque deberias ahcerlo en el Load de la pagina
si lo haces alli podrias suar el FindControl() sobre la row que quieres recuperar los valores para localizar el control
saludos
Esto no me esta funcionando. Sabras el porque?
Eliminarhola Leandro una pregunta como puedo crear un datatable y un gridview dinámicos q al momento de mandar datos en el datatable se llene el grid y aparesca
ResponderEliminaro un método lo que estoy haciendo que al seleccionar los checkbox de un gridview me manda a otra ventana con un textbox y un label para cada selección lo que yo quiero que también por cada selección me mande un datatable y aparesca el gridview con los datos de ese datatable solo que todo lo estoy haciendo dinamico agradecería tu ayuda
ResponderEliminarte mando mi código
List list = new List();
if (Session["ruta"] != null)
{
list = (Session["ruta"] as List);
foreach (Ruta ruta in list)
{
Panel panel = new Panel();
TextBox textbox = new TextBox();
Label eti = new Label();
textbox.Text = ruta.Id_Ruta.ToString();
Label salto = new Label();
salto.Text = "
";
eti.Text = "RUTA " + textbox.Text + "";
panel.Controls.Add(eti);
panel.Controls.Add(textbox);
pnlCuerpo1.Controls.Add(salto);
pnlCuerpo1.Controls.Add(panel);
}
}
Listpanel = new List();
if (Session["centro"] != null)
{
txtcentro.Text = (Session["centro"] as string);
}
}
}
hola alex
ResponderEliminarla verdad el concepto de seccion no se cual sera, pero si necesitas un datatable puedes crearlo y volcar los registros recorriendo las rows del gridview
DataTable dt = new DataTable();
dt.Columns("col1");
dt.Columns("col2");
foreach(GridViewRow row in GridView1.Rows){
DataRow dtrow = dt.NewRow();
row["col1"] = row.Cells[0].Text;
row["col2"] = row.Cells[1].Text;
dtrow.Rows.Add(row);
}
saludos
sesión sirve un ejemplo declaraste algo y para no volver a declararlo solo lo jalas con la session.
ResponderEliminarme salen los siguientes errores con tu código:
Error 1 No se puede utilizar como método el miembro 'System.Data.DataTable.Columns' no invocable.
y el otro
Error 4 No se puede aplicar la indización con [] a una expresión del tipo 'System.Web.UI.WebControls.GridViewRow'
y el otro:
Error 7 'System.Data.DataRow' no contiene una definición de 'Rows' ni se encontró ningún método de extensión 'Rows' que acepte un primer argumento de tipo 'System.Data.DataRow' (¿falta una directiva de uso o una referencia de ensamblado?)
y me aparece que no encuentra el gridview eso es xq no tengo uno pero xq lo quiero hacer dinamico
saludos espero me puedas ayudar gracias
ResponderEliminarhola alex
ResponderEliminarla verdad es que los error no me dicen mucho, ademas de ser algo raros, ya que algunos hacen referencia a un datatable lo cual no tiene nada que ver con el control gridview
lo que no entiendo es porque comentas que no tiene un gridview, que los campos sean dinamicos no quiere decir que no pongas un control gridview en el form
podrias plantear el problema en el foro
foro asp.net
donde plantees en que linea se produce el error
ademas de algo del codigo que estas implementando, te comento lo del foro porque por este medio poner codigo sera algo complicado
saludos
hola Leandro molestándote de nuevo
ResponderEliminarestoy creando mi gridview dinamico los datos los traigo de un datatable mi pregunta es como le puedo hacer´para que al momento que aparesca mi gridview en el aparesca checkbox gracias espero me puedas ayudar ya visite el foro y los link q me mandaste y nada de eso me ah servido espero me ayudes gracias
hola alex
ResponderEliminarsi las columans las defines de forma dinamica desde codigo deberias definir como se plantea en el articulo un ITemplate que defina ese checkbox
es mas en el articulo lo veras en la clase GridViewItemCheckTemplate
saludos
me podrias definir que es lo que tengo que poner de código pues soy nuevo y es mucho código realmente no se para que es todo mi código esta en el page load
ResponderEliminarespero me ayudes gracias
hola Leandro así te planteare mi pregunta esta mas clara
ResponderEliminarespero me ayudes con el código que debo asignar, tengo un problema... resulta que tengo un gridview(asp.net 2010) el cual es dinámico, se me ha pedido crear un nueva columna el cual contenga checkbox para selección múltiple.
gracias
hola alex
ResponderEliminarvalidaste el codigo de GridViewItemCheckTemplate
porque alli se define un checckbox en un template dinamico
saludos
Hola Leandro,
ResponderEliminarcomo le puedo hacer para que el control que definimos dinamicamente le genere su ID dinamico. por lo que entiendo el ID del Checkbox, siempre es el mismo para todos los que se generaron automaticamente.
como puedo hacer para que el ID de cada checkbox sea distinto trayendome el valor del campo [id] de una tabla. El campo tiene los valores identity.
en este caso seria algo como:
Check1
Check2
Check3
Check4
Check5
.
.
.
.
.
hola osvaldo
ResponderEliminarhasta donde se el propio asp.net es quien define el id (en realidad el ClientID) por lo que deberia variarlo, has inspeccionado el html resultante en el browser para ver si esto es asi?
saludos
hola Leandro me gusto mucho tu ejemplo yo estoy tratando de hacer algo similar
ResponderEliminartengo un menu dinamico q me muestra los datos de la tabla sublineas de la bd pero quiero que al dar clic en un producto de la sublinea me muestre en el formulario de productos todos los productos de ese producto de forma dinamica pero no se como hacerlo ¿podrias orientarme porfavor?
hola Liseth
ResponderEliminartienes un boton de seleccion definido en el GridView? porque si a este le defines el CommandName="Select", podrias usar el evento SelectedIndexChanged
en ese evento tomand el id que defines en el DataKeyNames, usnado el DataKeys, con el id ejecutarias la query
[ASP.NET][GridView] - Como seleccionar una fila
saludos
si es cierto lo intentare.Gracias por la ayuda.
ResponderEliminar!!!Bendiciones!!!
Hola Leandro,
ResponderEliminarMuchas gracias por tu ayuda. Tengo un problema, al momento de realizar el evento de actualizacion en la grilla, no me toma ningun control de los que se agregar dinamicamente a traves de estas clases, hay que hacer algo adicional??
Agrego la columna de la siguiente manera
Dim tmpNomProgramaEN As New TemplateField
Select Case Session("Idioma")
Case 1 : tmpNomProgramaEN.HeaderTemplate = New GridViewTemplate.GridViewHeaderTemplate("Name of the Program EN")
Case 2 : tmpNomProgramaEN.HeaderTemplate = New GridViewTemplate.GridViewHeaderTemplate("Nombre del Programa EN")
End Select
tmpNomProgramaEN.ItemTemplate = New GridViewTemplate.GridViewItemTemplate("programaEN")
tmpNomProgramaEN.EditItemTemplate = New GridViewTemplate.GridViewEditTextBoxTemplate("programaEN")
tmpNomProgramaEN.ItemStyle.HorizontalAlign = HorizontalAlign.Center
gvProgramas.Columns.Add(tmpNomProgramaEN)
y despues en el evento RowUpdating trato de recuperar los valores de la siguiente manera :
Dim txtEN As TextBox = DirectCast(gvProgramas.Rows(e.RowIndex).FindControl("txtprogramaEN"), TextBox)
Y me aparece el siguiente error:
Se produjo una excepción de tipo 'System.NullReferenceException'
Alguna sugerencia
hola Julián
ResponderEliminarpero estas seguro que defines el nombre correctamente, porque alli veo que haces
tmpNomProgramaEN.EditItemTemplate = New GridViewTemplate.GridViewEditTextBoxTemplate("programaEN")
y luego lo intntas buscar como
Dim txtEN As TextBox = DirectCast(gvProgramas.Rows(e.RowIndex).FindControl("txtprogramaEN"), TextBox)
o sea le has puesto un prefijo txt al nombre que antes no defines
no sera por esto que no lo encuentra
saludos
try
ResponderEliminar{
if (e.CommandName == "link2")
{
GridViewRow fila2 = (GridViewRow)((Control)e.CommandSource).NamingContainer;
String cod2 = GridView2.DataKeys[fila2.RowIndex].Values[0].ToString();
Ver_Pasajeros(cod2);
//int fila = 0;
//lblNroAsiento.Text = GridView2.Rows[fila].Cells[0].Text;
//lblPago.Text = GridView2.Rows[fila].Cells[3].Text;
}
}
catch (Exception)
{
}
tengo este codigo y al ejecutar el proyecto codigo me gustaria k al darle click a cada linkbutton,en los label me aparezca el nro d viaje y el costo d los viajes seleccionados asi tal km lo hacia en C# de escritorio
hola Ruben
ResponderEliminarlo primero que piedo comentar es que hacer esto
catch (Exception)
{
}
es una pesima idea, NUNCA se define un catch vacio porque despues tienes un error y no te enteras
si defines un catch usalo para transformar el error o para loguearlo a un archivo asi dejas el registro de lo que sucede
saludos
hola Ruben
ResponderEliminarque evento usas para trabajar el CommandName porque podrias usar el RowCommand
pero si usas esto no necesitas el NamingContainer
saludos
Hola estuve viendo tu código y me sirvió para crear los campos de manera manual y luego cargar el GridView, pero solo me carga una consulta cuando creo una nueva consulta, no me deja me sale error parece que los otros campos de la primer consulta quedaron asociados al Grid y no se como hacer para cancelar eso.
ResponderEliminarBoundField Fecha = new BoundField();
Fecha.DataField "AB_fechaTransaccion";
Fecha.HeaderText = "Fecha Transaccion";
GridViewReportes.Columns.Add(Fecha);
BoundField Nombre = new BoundField();
Nombre.DataField = "TE_razonSocial";
Nombre.HeaderText = "Nombre Tercero";
GridViewReportes.Columns.Add(Nombre);
BoundField Valor = new BoundField();
Valor.DataField = "AB_valor";
Valor.HeaderText = "Valor Abono";
Valor.DataFormatString = "{0:C}";
GridViewReportes.Columns.Add(Valor);
this.CargarGrillaAbonosDiarios();
este es mi código y esta consulta me corre, pero si muestro otra consulta diferente en este mismo grid, me sale error a pesar de que creo los otros campos, parece que los campos que cree anteriormente quedaron asociados al grid.
Hola a todos tengo un problemita que no he podido resolver, resulta que estoy cargando un GridView de la siguiente manera:
ResponderEliminarprotected void CargarReporteAbonosDiarios()
{
string conn = ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString;
SqlConnection cnn = new SqlConnection(conn);
DataTable dt = new DataTable();
cnn.Open();
SqlCommand cmd = new SqlCommand("PRC_REPORTES", cnn);
cmd.Connection = cnn;
cmd.CommandType = CommandType.StoredProcedure;
/*Variables para elegir la operacion y opcion de la misma a ejecutar. */
cmd.Parameters.Clear();
cmd.Parameters.Add("i_operacion", SqlDbType.VarChar).Value = "S";
cmd.Parameters.Add("i_opcion", SqlDbType.VarChar).Value = "E1";
cmd.Parameters.AddWithValue("i_FechaInicial", TxtFechaInicio.Text);
cmd.Parameters.AddWithValue("i_FechaFinal", TxtFechaFin.Text);
cmd.Parameters.AddWithValue("i_TE_US_id", (string)Session["id"]);
//Ejecutamos el procedimiento almacenado.
SqlDataReader dr = cmd.ExecuteReader();
GridViewReportes.DataSource = String.Empty;
GridViewReportes.DataSourceID = String.Empty;
dt.Clear();
dt.Load(dr);
GridViewReportes.DataSource = dt;
GridViewReportes.DataBind();
cnn.Close();
cnn.Dispose();
cmd.Dispose();
dt.Dispose();
}
Y resulta que necesito que después de que se cargue el Grid, me agregue una fila de ultima, en al cual van a ir los totales de los datos que cargue en el Grid anteriormente.
Mejor dicho yo lo que necesito saber es como insertar una fila en el GridView en blanco y después meterle los totales que capturo en el DataReader, en la posición que necesito, para que me quede como una especie de reporte, con sus precios y sus totales.
Este es mi GridView en HTML por si lo necesitan:
Los campos del GridView se los inserto de esta forma:
this.GridViewReportes.Columns.Clear();
BoundField Fecha = new BoundField();
Fecha.DataField = "FA_cFecha";
Fecha.HeaderText = "Fecha Creacion";
GridViewReportes.Columns.Add(Fecha);
BoundField Nombre = new BoundField();
Nombre.DataField = "TE_razonSocial";
Nombre.HeaderText = "Nombre Tercero";
GridViewReportes.Columns.Add(Nombre);
BoundField Subtotal = new BoundField();
Subtotal.DataField = "FA_subtotal";
Subtotal.HeaderText = "Subtotal";
Subtotal.DataFormatString = "{0:C}";
GridViewReportes.Columns.Add(Subtotal);
BoundField Iva = new BoundField();
Iva.DataField = "FA_ivaValor";
Iva.HeaderText = "IVA";
GridViewReportes.Columns.Add(Iva);
BoundField Abono = new BoundField();
Abono.DataField = "FA_abono";
Abono.HeaderText = "Abono";
Abono.DataFormatString = "{0:C}";
GridViewReportes.Columns.Add(Abono);
BoundField Total = new BoundField();
Total.DataField = "FA_subtotal";
Total.HeaderText = "Total";
Total.DataFormatString = "{0:C}";
GridViewReportes.Columns.Add(Total);
this.CargarReporteResumenCompras();
Muchísimas gracias por todo y espero me ayuden.
hola Emerson
ResponderEliminarsi quieres agregar una row adicional al grid debes ponerla en la entidad que asignas al datasource
ademas no uses esto
dt.Load(dr);
usa un DataAdapter
DataAdapter da = new DataAdapter(cmd);
da.Fill(dt);
a ese dt le agregas una ultima row usando
DataRow row = dt.NewRow();
dt.Rows.Add(row);
entonces al asignar al grid tendras una ultima fila
sino la otra es habilitar el footer del grid
Tutorial 15: Displaying Summary Information in the GridView's Footer
saludos
Hola Leandro,
ResponderEliminarpodrías decirme en vez de usar un DataAccess, cómo puedo usar mi cadena de conexión y en dónde implementarla?.
Lo quiero así porque pienso tomar mis datos de una base de datos pero con tu método solo admite listas.
Gracias
Espero puedas ayudarme
Este es mi código, te doy más detalle mira...
ResponderEliminarnamespace BLAH
{
public partial class Reuniones : System.Web.UI.Page
{
private void Page_Init(object sender, EventArgs e)
{
definirColumnasDocumentos();
}
SqlConnection Conexion = new SqlConnection("Data Source=BREMASS-AARON\\SQLEXPRESS;Initial Catalog=DBPrueba;Integrated Security=True"); // REALIZA CONEXIÓN
}
private void cargarDocumentos()
{
String str = "SELECT Descripcion,Vista,Descarga FROM documentos";
SqlCommand comando = new SqlCommand(str, Conexion);
Conexion.Open();
comando.ExecuteNonQuery();
SqlDataAdapter Da = new SqlDataAdapter();
Da.SelectCommand = comando;
DataSet Ds = new DataSet();
Da.Fill(Ds, "Descripcion,Vista,Descarga");
gridDocumentos.DataSource = Ds;
gridDocumentos.DataBind();
Conexion.Close();
}
private void definirColumnasDocumentos()
{
gridDocumentos.Columns.Clear();
BoundField columna = new BoundField();
columna.HeaderText = "Vista";
columna.DataField = "Vista";
gridDocumentos.Columns.Add(columna);
}
}
Al momento de hacer esto, tal y como está la tabla de SQL así me la muestra, agrego la columna pero me la agrega al inicio, lo que quiero hacer es:
1. Agregar la columna al final para que sea mostrada como linkfield
2. No mostrar las columnas Vista y Descarga, ya que esas las quiero convertir a linkfield
Te comento que me marca error al querer hacerlo como tú, ya que solo acepta listas, podrías ayudarme.
Gracias de antemano
hola Aaron
ResponderEliminarrecuerda que tienes que definir la propiedad
gridDocumentos.AutoGenerateColumns = false;
con eso si defines las columnas solo se mostraran estas y no se generarn las automaticas
saludos
Excelente, funciona!!.
ResponderEliminarGracias
Hola Leandro.
ResponderEliminarEl articulo es bastante útil pero tengo un problema y es que cuando cambio la página del gridView se me pierden los datos de la columna.
Muchas Gracias
hola ritoscue
ResponderEliminares que los datos debes conservarlos cuando cambias de pagina
[ASP.NET] Mantener información al cambiar de pagina
saludos
Hola Leandro.
ResponderEliminarTengo una consulta.
Yo cargo los datos de una base de datos y no de una lista. Todo parece que funciona perfectamente hasta que intento buscar el control en el evento Row_Updating,
y lo que he observado es que me desaparecen todas las celdas del gridview, aunque en pantalla tengo la información, si consulto e.row.cells esta a 1,. Como te comento yo tanto las cabeceras como los datos los cargo dinámicamente de la base de datos.
Sabrías porque puede ser??
Muchas Gracias.
Saludos
Leandro Buen día
ResponderEliminarImplemente tu ejemplo para crear un control de usuario pero necesito manipular el texto que se inserta en los TextBox que se crearon en la clase GridViewHeaderTemplate : ITemplate como puedo pasar ese valor al CodeBehind del control intente por medio de variables de Sesion y creando métodos públicos pero no me ha funcionado me puedes sugerir algo?.
Saludos
hola OscarMC
ResponderEliminarsi es una columna de template deberias usar el FindControl() para localizar el control que esta dentro de la row,
como ser
TextBox txt = row.FindControl("TextBox1") as TextBox;
conociendo la row podrias buscar el control que contiene y define la columna de template
saludos
Hola!! primero que nada muchas gracias por este post, la información es muy buena y me ha ayudado mucho, pero tengo una duda, me gustaría saber como hace la recuperación de los datos que ingresa el cliente, ya que al hacer el postback en mi caso pierdo esa información, de ante mano muchas gracias.
ResponderEliminarDisculpa tengo una duda, checke el código y no entiendo en que parte declaraste la variable Session["Datos"],
ResponderEliminarel programa ya no se puede descargar ojala me puedas orientar.
hola Sakurita
ResponderEliminaractualice la publicacion del codigo
saludos
hola Jackeline
ResponderEliminarsi ese es uno de los principales problemas cuando se genera codigo de forma dinamica
una forma simple es tomar el dato directo del objeto Request
aunque tambien podrias evaluar aplicar la tecnica
Cómo: Crear dinámicamente controles en ASP.NET utilizando .NET Visual C#
como veras en cada request los controles dinamics debes volver a crearlos para poder accederlos
saludos
Hola Leandro.
ResponderEliminarEstoy implementado un gridView con columnas checkbox dinámicas siguiendo el patrón de diseño que has colgado en la web.
Se generan perfectamente.
Dejo pulsar varios checkbox y mi intención es controlar las que han pulsado y registrarlo.
El problema viene que cuando ejecuto el método FindControl, tal como tu comentas, no me encuentra los controles checkbox, solo devuelve null, o sea que no lo encuentra.
He Observado en tu ejemplo que el orden de eventos es:
1-Page_Init
2-evento InstantiateIn de la plantilla checkbox
3-Page_load.
y asi veo que funciona.
Pero en mi programa el orden de los eventos es:
1-Page_Init
2-Page_load.
y no se produce el evento InstantiateIn por lo que no se carga bien el gridView y luego no funciona FindControl.
¿Alguna sugerencia?
Hola Leandro.
ResponderEliminarComo puedo localizar las columnas ya que no me funciona el método FindControl.
¿Hay alguna otra forma? Porque, si recorro el grid me indica que tengo 4 registros, pero no puedo localizar los checkbox utilizando FindControl.
Estimado, estoy utilizando tu código el cual funciona muy bien para crear el GridView pero al momento de recuperar el dato no me lo trae siempre en NULL
ResponderEliminarstring FECHAENTREGA = (row.FindControl("txtFECHAENTREGA") as TextBox).Text;
El GV lo cargo asi:
DefinirColumnas((DataTable)Session["Table"]);
GridView1.DataSource = Session["Table"];
GridView1.DataBind();
Y definir columnas lo arme de este modo.
GridView1.Columns.Clear();
for (int i = 0; i < 7; i++)
{
TemplateField temp = new TemplateField
{
HeaderTemplate = new GridViewHeaderTemplate(table.Columns[i].ToString().ToString().Trim().ToUpper()),
ItemTemplate = new GridViewItemTemplate(table.Columns[i].ToString().Trim().ToUpper())
};
GridView1.Columns.Add(temp);
}
//Columnas dinamicas
for (int i = 7; i < table.Columns.Count - 3; i++)
{
TemplateField temp = new TemplateField
{
HeaderTemplate = new GridViewHeaderTemplate(table.Columns[i].ToString().ToString().Trim().ToUpper()),
ItemTemplate = new GridViewItemTemplate(table.Columns[i].ToString().ToString().Trim().ToUpper()),
EditItemTemplate = new GridViewEditTemplate(table.Columns[i].ToString().ToString().Trim().ToUpper())
};
GridView1.Columns.Add(temp);
}
for (int i = table.Columns.Count - 3; i < table.Columns.Count; i++)
{
TemplateField temp = new TemplateField
{
HeaderTemplate = new GridViewHeaderTemplate(table.Columns[i].ToString().ToString().Trim().ToUpper()),
ItemTemplate = new GridViewItemTemplate(table.Columns[i].ToString().ToString().Trim().ToUpper())
};
GridView1.Columns.Add(temp);
}
Donde puedo adjuntar lo que personalice para que tengas más detalle?
buenas tardes Alex, tengo una consulta, me encuentro realizando gridview de forma dinamica, sin embargo cuando agrego la opcion de paginado y agrego el evento pageindexchanging , al seleccionar un boton del paginado el evento no funciona tendras algun ejemplo de como realizar un griview con paginado de forma dinamica? de antemano muchas gracias quedo pendiente de tus publicaciones
ResponderEliminar