lunes, 2 de abril de 2012

ASP.NET–GridView anidados (maestro-detalle) (GridView nested)

 

Introducción

El objetivo en el articulo será el demostrar como armar un grid con jerarquía, en este caso mostrando las ordenes de compra de un cliente

Además se pretende demostrar como se puede armar una entidad compleja que retorne los datos en una estructura anidada de listas

 

Detectar despliegue detalle

Uno de los puntos mas importantes en la implementación esta relacionado con la forma en que se detecta el expandir\colapsar del detalle

En la imagen se remarcan dos atributos creados con este propósito, la idea es poder relacionar la imagen con el tag <tr> que permite ocultar o mostrar el grid del detalle

La idea detrás de esto es ayudar luego a jquery para poder determinar que elementos intervienen en la acción

con jquery se extrae el id de la orden, para luego usarlo de selector del <tr> que posee ese mismo id

el toggle() solo permite switchear entre visible\invisible, y detectando el estado mostrar una imagen u otra

 

Estructura de datos jerárquica

La estructura usada para el modelo relaciona tres clases

La idea es mostrar como al cargar los datos, es analizar como los métodos se invocan unos a otros para recuperar la info enlazada en al jerarquía

 

Código

El codigo fue confeccionado con Visual Studio 2008 y base de datos Sql Compact 3.5

[C#]
[C# SkyDrive]

85 comentarios:

Adri dijo...

Buenas!
Antes de nada, darte las gracias por todas las dudas que tu blog me ha solucionado.

A ver si me doy explicado con claridad para saber si me puedes solucionar el problema que tengo.

Necesito tener un gridview en el que:
-En la Columna(0) se muestren los valores de una consulta sql (en este caso serían los colores disponibles en almacén de un articulo)
-En la fila(0) se muestren los valores de otra consulta sql (en este caso las tallas disponibles en almacén de un articulo)

Leandro Tuttini dijo...

hola Adri

y no podrias lograr eso usando el evento RowDataBound ?

o sea asignas al datasource del grid el resultado de la query de las filas

y en el RowDataBound tomarias la primer columna, ejecutarias la otra query y asignarias los colores a esa columna seleccionada para esa fila que se crea

saludos

Adri dijo...

Al final no puedo hacer nada de eso porque el tipo de datos me lo imposibilita mediante una consulta... :S

Ahora me surgió otra duda... Hay alguna manera de copiar un dataset en un Array? como sería? nunca trabajé con vectores y no me doy acostumbrado a ellos..

Gracias!

Leandro Tuttini dijo...

hola Adri

un dataset a un array ?
la verdad no lo recomendaria

podrias si definir uan clase con sus propiedades y generar una lista genrica de esta clase

entonces recorrer las filas del datatable y volcar cada campo a las propiedades

saludos

Julio dijo...

Hola, una pregunta, el ejemplo sirve para un anidamiento recursivo, estoy buscando la manera de armar una aplicacion para el registro de actividades que a su vez puede tener subactividades (que es una misma entidad "Actividad") y a su vez esta otra subactividad...etc. No encuentro la manera de solucionar esto. Raro que haya mas de 3 anidadas, pero se podria dar el caso. Tenes alguna idea de como podria mostrar esto? La estructura ya la tengo armada, la entidad actividad tiene un IDPadre, con esto se si es una subactividad, si es cero es una actividad raiz. Cualquier ayuda se agradece, estoy con esto a modo personal hace meses y no le encuentro la vuelta con el Gridview ni con controles de terceros, mas que nada para mostrarlo en modo de jerarquia por Actividad, o sea Actividad -> subactividad (si existe) -> subatividad de subactividad, etc...Espero haberme explicado Saludos.

Leandro Tuttini dijo...

hola julio

podria funcionar si sabes que los niveles son fijo, o sea si dices los niveles son siempre 3 o 4 y defines el html del gridview para soportar esta situacion

pero hacerlo dinamico que algunas entidades tengan 2 niveles, otras 4 y asi las variantes los veo complicado

se podria definir en el html del grid los niveles maximos que se puede alcanzar y de ultima si solo se llega al segundo nivel dejar los grid contenido sin asignar el DataSource, como son gridview sino asignas info no se muestra el grid

pero la verdad esto no lo he probado

saludos

Carolina Buitrago dijo...

tengo una pregunta y es la siguiente: ya hice unas modificaciones segun lo q requiero y al visualizar el proyecto, me sale esto: "breaking on JScript runtime error -'$' is undefined" y hace referencia a esta secuencia:

$(function().

que debo hacer?
gracias.

Carolina Buitrago dijo...

ya solucioné el error y era q tenia un ( de más.
Pero ahora me sale esto: validation (XHTML 1.0 Transitional): Attribute 'orderid' is not valid attribute of element 'img' y no me muestra la tabla.

HammerTech dijo...

muchas gracias Leandro, su explicación me ha servido para solucionar un marronceteme guardo su blog para el futuro

Georgina Galdámez dijo...

Hola Leandro!!
Disculpa por preguntarte en este espacio pero no haye donde mas hacerlo, mi pregunta es un poco afuera de este tema pero algo relacionado: ¿es posible correr una aplicación asp.net en windows server 2008 (ISS 7) hecha en un windows XP + VS 2000 (framework 1.0 creo q es)? En caso que sea negativo, me imagino que no se puede migrar la aplicación a VS 2010?

Leandro Tuttini dijo...

hola Georgina

imagino usas .net 1.1

quizas esto de una pista

How to install ASP.NET 1.1 with IIS7 on Vista and Windows 2008


saludos

Georgina Galdámez dijo...

Muchas gracias Leandro, el link me da error pero ahora sé qué tema buscar, y al parecer si se puede, gracias por aclarar mi duda

Leandro Tuttini dijo...

que raro se publico incorrecto el link
ahi va de nuevo

How to install ASP.NET 1.1 with IIS7 on Vista and Windows 2008

Georgina Galdámez dijo...

este ultimo que pusiste si abre, intentaré instalarlo, mil gracias

DANIEL GONZALEZ dijo...

Buen dia Leandro.
Necesito crear un grdview que cargue de una tabla sql datos, que por su valor los coloque segun la columna y fila que corresponda.
y lo que mas me complica, es que, es posible que la celda deba contener mas de un dato a la vez (Maximo 4 datos).
Basicamente es un tablero de alarmas.
Me podras dar una idea de como armarlo por favor?
Puedo pasarte el diseño modelo en excel de lo que quiero hacer para una mayor idea.
Te dejo un abrazo y muchas gracias!!!

Leandro Tuttini dijo...

hola Daniel

lo que recomendaria es que pases la info que tomas de la db a clases que tu crees y uses esto para personalizar la info que mostraras

recuerda que en una clase pdorias hacer

public class Datos{

public string dato1 {get;set;}
public string dato2 {get;set;}
public string result {
get {return this.dato1 + this.dato2;}
}

}

como veras con lcases puede crear columnas complejas en base a otras
en esas podrias armar la info que necesitas para unir varias columnas en una

por supuesto en el gridview deberias luego definir als columnas en timepo de diseño y mapear la columna compuesta nueva que creas

saludos

Murray3G dijo...

Hola Leandro, la verdad que supera todo lo que yo se ya que estoe s un hobbie para mi, soy medico en realidad, te queria preguntar una duda sobre una base en access 2003 que estoy hacieno:
lleno un par de tablas desde un formulario, el cual tiene datos en algunas cajas de textos con datos predefinidos pero que puedo modificar, dentro de estos textbox hay 2 que son fecha y hora, cuando la informacionn esta lista para meter en la tabla presiono un botón para que esta se guarde en su respectiva tabla con 4 campos entre los que están fecha y hora, el tema es que necesito que esa fecha y hora no se repitan nunca, osea que me avise que esa hora de esa fecha ya esta ingresada en la tabla y que no ingrese los datos hasta que no ponga datos validos.
Espero haberme explicado, la verdad no se como hacer con código o sql o ambas, muchas gracias.
Gracias

An Lel dijo...

Tengo una duda espero me puedan ayudar estoy trabajando con Visual Studio 2005 y quiero hacer lo siguiente:
Quiero llamar a un formulario cuando este posicionado en un textbox, les explico.

Tengo un textbox1 un botón1 y un textbox2 el textbox1 es el que esta habilitado el botón y el tetxbox2 el focus no pasa en ellos, entonces lo que necesito es llamar a un formulario que se llama "FormProducto" el cual contiene un Datagrid dos botones uno es para salir del formulario y el otro es para Aceptar, en el cual el DataGrid tiene dos columnas una que se llama Código en donde me aparece los códigos de los productos y la otra columna que se llama descripción, entonces quiero que cuando me aparezca el formulario de los productos pueda elegir el código, y dar aceptar en el boton para pegar el codigo en el textbox1 y la descripcion en el textbox2, y que ademas yo pueda llamar al formulario presionando la tecla F4 y también que esta función solo suceda cuando este posicionado en el textbox1, porque quiero hacer esta función en el textbox3, presionando la tecla F4, creo que el botón es para realizar esa clase de función, pero aun no he podido saber como se hace.

Ademas quisiera que sin necesidad de llamar al formulario donde están los productos solo pueda escribir el código en el textbox1 y que automáticamente me aparezca la descripción del código que corresponda en el textbox2, me quedo en espera de sus respuestas.

Leandro Tuttini dijo...

hola Murray3G

lo que podrias ahcer es validarlo

[ADO.NET] – Parte 5 - Ejemplos Simples – Operaciones CRUD

usar la misma tecnica que se aplcia en el articulo, si se que este usa sql server, pero casi no hay diferencia en el codigo, solo es cuestion de cambiar el Sql y poner el OleDb, por ejemplo en lugar de SqlConnection usar OleDbConnection, el resto si cambias las clases es identico

entonces habria que centrars en el metodo Exists() si bien allis e valida un id se podria aplicar lo mismo si se pone un campo fecha o cualqueir otro, si existe devolvera registros por lo tanto devolvera true y en la validacion previo a grabar lo informas y no grabas nada

saludos

Leandro Tuttini dijo...

hola An Lel

bueno al verdad son bastante cosas

lo primero que podria comentarte es que analice como comunicar los formularios

[DataGridView] Parte 3 – Pasaje de información entre grillas en distintos formulario

con la info del link podras pasar la seelccion del grid de un form a otro

despues lo de detectar el F4 se logra por medio del ProcessCmdKey

Protected Overrides Function ProcessCmdKey( _
    ByRef msg As System.Windows.Forms.Message, _
    ByVal keyData As System.Windows.Forms.Keys) As Boolean
       
        If (Not TextBox3.Focused) Then _
           Return MyBase.ProcessCmdKey(msg, keyData)
      
        If (keyData <> Keys.F4) Then
            Return MyBase.ProcessCmdKey(msg, keyData)
  End If
      
'aqui el codigo
           
        Return True
End Function

como veras solo si el textbox3 tiene el foco y si se presiono F4 es que se pasa y realiza la accion

saludos

Anonimo dijo...

Hola leandro, antes que nada gracias por la data muy bueno el articulo.
Te queria preguntar, yo ya arme mas o menos todo pero cuando clikeo en la imagen no responde como si no detectara el evento. Tendria que agregar un evento onclick en el tag de la imagen?. Saludos y gracias!

Leandro Tuttini dijo...

hola

claro debes usar jquery para asignar el evento, en la imagen 3 de articulo veras que se muestra

$('#<%=gvOrders.ClientID%> img').click(...

eso es la seleccion de las imagenes del grid para asignar el click que permite expandir o colapsar

valida que ese evento se este generando

saludos

Daniel Portada Zecua dijo...

Hola muy buena información me resolvió mi problema... Pero tengo una pregunta: el codigo javascript que colocas ($('#<%=gvOrders.ClientID %> img').click(function) funciona bien si esta dentro del mismo aspx, pero al pasarlo a un archivo .js y llamar este desde el aspx JqUERY manda este error "Syntax error, unrecognized expression: %" y no funciona el despliegue.

Leandro Tuttini dijo...

hola Daniel

es que si lo usas desde un .js debes adaptarlo
hay varias formas quizas la mas directa seria usando

$("[id*='gvOrders'] img")

con el *= localizas el control por aproximacion en el nombre del id

saludos

MIGUELL.. dijo...

mira Sr. Leandro tengo este dilema:

Tengo un gridview1 en una de sus columnas un checkbox, si lecciono 1 o varios checkbox 1 ó 2 ó mando a cosnultar a mi bdd y lo que quiero haces es por cada checkbox seleccionado me genere gridview dentro de una fila recordando que la se pudieron seleccionar 1 o varios checkboxs. No se si estoy atacando mal el problema. Espero me orientes...

Leandro Tuttini dijo...

hola MIGUELL

que uses check o imagenes es indistinto, porque el grid y el arbol relacionado se genera al mismo tiempo con el uso del RowDataBound

no se si los check lo usarias para colapsar o no el detalle pero no afecta a como generas el detalle

saludos

William José Sánchez Gutiérrez dijo...

Excelente referencia Leandro. Me ha sido de mucha utilidad. He logrado incrustar un tercer grid; sin embargo no logro que este tercero se expanda y colapse. Creé una función Javascript 'idéntica' a la que expande el segundo grid, teniendo cuidado de cambiar el nombre correcto del grid y columna, pero no funciona. ¿Alguna sugerencia?

Leandro Tuttini dijo...

hola William

has validado si la accion de javascript se lanza ?

podrias poner la linea

debugger;

en javascript para que se deterna la eejcucion alli y puedas inspeccionar el codigo

en el articulo uses el clientid del gridview y el img para asignar el click de la opcion que muestra o no el desplegable, el tema es con un tercer nivel esto como lo asignaste ?
porque no me cierra tan directo para obtener el tr que se cierra, porque no aplicaria sobre el clientid del primer grid sino sobre el segundo


saludos

William José Sánchez Gutiérrez dijo...

Hola Leandro, gracias por contestar. Siguiendo las pistas que me diste he dado con la solución. Acá te explico cual era el problema.
Verás tengo la siguiente estructura
- gvMaestro
- gvDetalle
-gvSubDetalle
Para expandir y colapsar tanto el gvDetalle y gvSubDetalle creé funciones exactas a la de tu ejemplo.
Esta para el gvDetalle funciona sin problemas
[code]
$(function() {

$('#<%=gvMaestro.ClientID %> img').click(function() {

var img = $(this)
var IdMaestro = $(this).attr('IdMaestro');

var tr = $('#<%=gvMaestro.ClientID %> tr[IdMaestro =' + IdMaestro + ']')
tr.toggle();

if (tr.is(':visible'))
img.attr('src', 'Images/minus.png');
else
img.attr('src', 'Images/plus.png');

});

});
[/code]

En la segunda función sustituyo gvMaestro por gvDetalle, así:
[code]
$(function() {

$('#<%=gvDetalle.ClientID %> img').click(function() {

var img = $(this)
var IdDetalle = $(this).attr('IdDetalle');

var tr = $('#<%=gvDetalle.ClientID %> tr[IdDetalle =' + IdDetalle + ']')
tr.toggle();

if (tr.is(':visible'))
img.attr('src', 'Images/minus.png');
else
img.attr('src', 'Images/plus.png');

});

});
[/code]

Acá el compilador arrojaba el siguiente error: "El nombre 'gvDetalle' no existe en el contexto actual". Ante esto habia optado eliminar la función y dejar el gvSubDetalle siempre visible.

Siguiendo tu recomendación inspeccioné con ayuda de Firebug y pude notar que el ClienteID que se asigna a gvDetalle nos es simplemente "gvDetalle" sino que aperecía como "gvMaestro_ctl02_gvDetalle"; así que sustituí en la función <%=gvDetalle.ClientID %> por gvMaestro_ctl02_gvDetalle y funcionó a la perfección.

Aunque me quedé con la espina de no poder extraer el ClientID dinamicamente, gracias a tus sugerencias he resuelto mi problema.

Ahora bien, ¿Sabes como podría obtener dinamicamente de gvDetalle el ClientID?

Muchas Gracias.

Alex Yordano Aguilar Cabello dijo...

Hola leandro en el codigo javascript $('#<%=gvDetalle.ClientID %> img').click(function() ...


no entiendo muy bien como lo usas ya que el ClientID es parte del archivo js o lo as aumentado? no se si me podrias explicar acerca de eso muchas gracias por tu respuesta

Leandro Tuttini dijo...

hola Alex

aqui
[jQuery] Por donde comenzar

explico sobre este tema

saludos

greg_dorian dijo...

hola leandro super este tema pero BUSCO ALGO ASI EN WindowsForms!!!

no he podido encontrar algo de codigo para utilizar datagrid anidados. lo mas cercano a lo que quiero es esto

http://msdn.microsoft.com/es-es/library/fxfa9793%28v=vs.100%29.aspx
ya he hecho joins en consultas y llevarlos al dataset, y tambien hacer relations en los Datatable pero no logro hacer que mi datagrid muestre la tabla1 con la tabla2 del link arriba mencionado.

Leandro Tuttini dijo...

hola

no recomendaria usar ese control, si has leido la documentacion el primer parrafo dice muy claro que este control solo se dejo por compatibilidad, que deberias usar el datagridview

quizas algo como esto:
Hierarchical DataGridView in C#

saludos

Poulette Lopez Hernandez dijo...

HOLA:
Primero que nada, felicitaciones por tu blog, me gusta como explicas, yo tengo una duda, como se exporta una tabla asi en excel, que guarde los campos principales y a la vez los campos del gridview anidado?Espero contestacion. Saludos!!!

Leandro Tuttini dijo...

hola Poulette

sin usar el excel o las librerias COM de office requiere de algun otro componente como ser

http://closedxml.codeplex.com/
o sino
http://npoi.codeplex.com/

estos estan basados en openxml por lo que podrias suarlos sin encesidad de office local en la pc donde se debe exportar

saludos

Poulette Lopez Hernandez dijo...

hola: gracias por la contestacion, ya los cheque. Ahora me surge otra duda, me podrias dar un ejemplo de como ingresar otro gridview dentro del grid anidado?, por que ya estube checando y no me queda claro como hacerlo, de antemano gracias por tu ayuda

Leandro Tuttini dijo...

hola Poulette

es que la tecnica es la misma que aplicarias al primer grid anidado, solo que la repiten usando el evento RowDataBound pero del segundo grid para localizar dinamicamente al que tendria como hijo

o sea se repite lo que ya se realizo solo que en un siguiente nivel

saludos

Oscar Mendoza dijo...

Hola Leandro tienes el codigo en VB?

Leandro Tuttini dijo...

hola Oscar

la verdad no implemente el ejemplo en vb.net

pero podrias ayudarte con tools como ser

Convert c#

para convertir el codigo

saludos

camilo molina canales dijo...

Hola Leandro,
tengo una duda, ambas grillas se deben cargar al mismo tiempo mediante el RowDataBound, de la primera?

o se pueden cargar dinamicamente, y me refiero con esto a que si se puede clickear un imagebutton, ya sea html o y que al momento de clickear obtengo los datos de la fila y en base a un código contenido en esta me cargue la segunda grilla?

Saludos

Leandro Tuttini dijo...

hola

como esta planteado en el articulo se cargan a la primera

podria realizarse alguna carga lazy cuando expandes

pero si necesitas algo como eso aconsejaria pienses un unsa un mejor control como ser jQGrid

http://www.trirand.net/demoaspnet.aspx

analiza el Hierarchy de la demo
lo descargas de aqui
jqgrid download


saludos

Luis R C G dijo...

Buen dia Leandro, primero que nada te agradezco por tus post ya que me han servido mucho, tengo una duda acerca de tu tutorial de gridviews anidados, primero que nada uso VB estoy creando una aplicacion donde requiero Maestro - Detalle y la idea de que sea anidado me parece excelente a punta de leer y leer e llegado a cargar la informacion del maestro en la grilla, habilitando la seleccion y edicion mediante dropdownlist, quize pasar al detalle basandome en tu tutorial pero solo logro llegar hasta el punto de agregar los Gif y programar el click ellos mediante jquery, yo uso sqldatasource y Datatables para llenar la grilla, hay manera de adaptar mi necesidad a lo que tu haces en tu tutorial, de ser asi me podrias orientar en que puntos claves debo investigar y estudiar. De antemano gracias :)

Leandro Tuttini dijo...

hola Luis

el tema esta en como resolverias el evento RowDataBound, no se si lo has analizado pero alli se hace uso de una linea muy importante como es

Order order = (Order)e.Row.DataItem;

esa linea devuelve la entidad que define la row que se crea en el grid padre, que al estar ya cargado evitas volver a ir a la db para consultar

quizas si lo haces como planteas en ese punto podrias tomar ltos que se genera y definir el parametro del SqlDatasource del grid relacionado para que genere el filtro para el grid hijo

o sea de alguna forma en ese evento deberias poder indicar como resolver los datros del grid detalle, creo que se podria realizar, pero esa parte del evento va a cambiar bastante

saludos

Luis R C G dijo...

Buenas tardes Leandro yo aqui molestando de nuevo con 2 consultas, me ha servido de mucho tu ejemplo y te agradezco mucho:
La primer duda es la siguiente.- No consigo hacer que mediante el click al .GIF se despliegue el TR con el contenido del Gridview Hijo, le quite el display:none y si veo la informacion de todos los gridview hijos correctamente cargada, pero no puedo desplegar o contraer el TR. No se que me pueda estar faltando ya que sigo tu ejemplo.

Y la otra duda es, que si puedo editar la informacion que esta en el gridview hijo, ya que no he podido abrir los eventos de ese gridview al parecer me marca como si no estuviera declarado ya que se encuentra en un template el gridview padre, no se que fuera necesario para poder hacer esto ya que si necesito editar la informacion del gridview hijo.

Ya te escribi toda una carta, espero me puedas ayudar y de antemano muchisimas gracias, saludos :D

Leandro Tuttini dijo...

hola Luis

has validado que el evento de javascript se este eejcutando ?

podrias poner un alert() de javascript o usar el

debugger;

para poder detener el codigo y validar que se ejecute el evento

Poder se puede suar los eventos del gridview hijo, pero si lo realizas desde el diseñador necesitas editar el temaplte

Using TemplateFields in the GridView Control (C#)

analiza de la figura 5 a la 7

saludos

Luis R C G dijo...

Buenas tardes Leandro, aqui molestando de nuevo jeje te cuento que ya pude hacer que se contraiga y expanda el Detalle, lo unico que me falta es lo de la edicion en el Gridview Detalle, en la parte del Code Behind solo me aparece el evento SelectedIndexChanged.

No me aparece el RowDataBound ni ningun otro, que son los que necesito para editar la informacion, no se a que se deba o que me recomiendes hacer, consulte el link que me dejaste en el comentario anterior pero no me quedo muy claro, no se si me explique muy bien.

De antemano gracias han sido excelente tus tutoriales me han ayudado mucho, y si pudieras orientandome con ese detalle te estaria muy agradecido en verdad.

Luis R C G dijo...

Se me olvido decir, que en el Gridview Padre si salen todos los eventos en el Code Behind, en el Gridview Detalle es donde solo me aparece SelectedIndexChanged.

Leandro Tuttini dijo...

hola Luis

si editas el template deberias tener acceso al gridview hijo y a sus eventos

Tutorial 12: Using TemplateFields in the GridView Control

analiza las imagens 5 y 6
al editar el item template accedes al control que este contiene

saludos

Luis R C G dijo...

Hola Leandro buen dia, muchas gracias por tus respuestas, he estado analizando el link que me proporcionaste y no percibo la diferencia o la parte que me falta para poder usar los eventos del Gridview Hijo y asi poder editar su informacion. Si es de un poco mas ayuda te dejo unos screenshots de como se ve mi proyecto.
En la primer imagen se aprecia que el Grid Hijo esta dentro del Template Field de Padre.
http://i1274.photobucket.com/albums/y429/rodo0387/1_zps88ee417c.jpg

En la segunda imagen se aprecia cuales eventos salen para el Grid Hijo.
http://i1274.photobucket.com/albums/y429/rodo0387/2_zps6781800e.jpg

No se si con esto pudieras darme un direccion de que hacer o que investigar o bien que otro metodo me convendria usar para realizar lo que necesito, de antemano muchas gracias Leandro, saludos.

Leandro Tuttini dijo...

hola Luis

pero alli no es donde debes ver los eventos, alli solo se listan los eventos que declaraste no los que podes usar

tenes que ir a la primer imagen que muestras y alli selecciona el grid hijo en la edicion de template

si vas al cuadro de propiedades veras un icono con forma de rayo amarillo, alli estan los eventos que puedes definir

pero repito selecciona el grid que esta dentro del template o sea estan do en la priemr imagen que has puesto

saludos

Roberto dijo...

Hola Luis, gracias por el articulo.
Te hago algunas preguntas:
1) Como hago para recorrer la gridview hijo? Ya que para mi desarrollo necesito guardar en la BD un campo determinado de la tabla hijo.
2) Agrego un dropdownlist en gridview hijo desde HTML. Ahora quiero llenar los datos que van a dropdownlist desde code behind(c#).
Como lo puedo implementar?

Gracias.-
Slds.-

Leandro Tuttini dijo...

hola

1-
para recorrer un gridview hijo primero deberias poder seleccionar ese control, lo que no comentas es en que accion estas queriendo realizar esto? pero si tienes la row con la cual trabajar podrias hacer un FindControl() co el nombre del gridview hijo, asi lo localizas y recorres las filas

foreach(GridViewRow row in GridView1.Rows){

}

2-
esto implicaria el paso anterior mas uno adixional que seria tomasr nuevamente con el FindControl() del dropdownlist, el tema es qe nuevamente no mencionas en que evento quieres lograr esto, si es en el ItemDataBound del grid hijo podrias aplciarlo ya que se da este evento por cada fila, usarias el e.Row y alli buscas por el combo para cagarlo

saludos

Roberto dijo...

Gracias Leandro por responderme.

1)Tengo tabla maestra pregunta y su tabla hija respuesta. Cada respuesta tiene un puntaje. Que de acuerdo al cuestionario puede ir de 0 a 10 o 0 a 100. Entonces el evaluador debe poner la nota(dropdownlist de notas). Entonces debo tomar el idrespuesta(tabla hija) y guardar la nota de acuerdo al idrespuesta.
Así con todas las respuestas.
Lo debo hacer en el evento Btn_Guardar_Click(), recorriendo el gridview(hija) y tomando los idrespuesta y notas.

2) Desde if (!IsPostBack)
{
de acuerdo al cuestionario, me traigo las notas de 0 a 10 o 0 a 100
}
Luego en el evento gv_preguntas_RowDataBound, de el gridview padre lo lleno:

Control ctrl = e.Row.FindControl("CmbNotas");

if (ctrl != null)
{
DropDownList dd = ctrl as DropDownList;
dd.DataSource = DataNotas.Tables[0];
dd.DataValueField = "Id";
dd.DataTextField = "Descripcion";
dd.DataBind();

}
Esto anda perfecto, pero me gustaría que este combo este en el gridview hijo, al lado de la respuesta. Luego si todo anda bien, recorrer ese combo, tomar el idrespuesta y grabar en la BD desde un button_click().

Muchas Gracias.-






Roberto dijo...

Me auto respondo je:

1)
foreach (GridViewRow grd_Row in this.gv_preguntas.Rows)
{
GridView GridView2 = (GridView)grd_Row.FindControl("gv_respuestas");
int idrespuesta = Convert.ToInt32(GridView2.Rows[0].Cells[0].Text.ToString());
DropDownList notas;
notas = (DropDownList)GridView2.Rows[0].Cells[2].FindControl("CmbNotas2");
idnota = Convert.ToInt32(notas.SelectedItem.Value);
camponota = Convert.ToString(notas.SelectedItem.Text.Trim());

}

2) En la gridview hija(HTML), agrego:
OnRowDataBound="gvChild_RowDataBound"

En C#:
protected void gvChild_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{

Control ctrl = e.Row.FindControl("CmbNotas2");
if (ctrl != null)
{
DropDownList dd = ctrl as DropDownList;
dd.DataSource = DataNotas.Tables[0];
dd.DataValueField = "Id";
dd.DataTextField = "Descripcion";
dd.DataBind();
}
}
}

Gracias..Slds.-



Franco Vargas dijo...

Hola buenas noches y como hago para paginar el gridview que esta dentro del gridview

fernando yevenes dijo...

genere un código muy similar para vb.net ... yo programado en C# pero ademas en vb .. la lista enlazada no tengo problema pero si tengo que poder interpretar el gvProducts_RowDataBound

para desplegar el detalle si no no funciona ....

me puedes hechar una mano
cambie el GetAllOrdersByCustomer

el String SQL

string sql = @"SELECT OrderId,OrderDate,
RequiredDate,ShippedDate,
ShipVia,ShipName
FROM Orders
WHERE (@customerid = -1 or orderId = @customerid)
";

aunque lo abrias generado como un store procedure ....

saludos

zeroyevi@hotmail.com

Leandro Tuttini dijo...

hola fernando

no entendi del todo la problematica, segun veo vas a usar el evento RowDataBound de una tabla de productos, pero que problema hay con la query que planteas?

parece estar correcta, si desde codigo asignas el parametro deberia retornar los datos para cargar el grid anidado

recuerda usar el DataKeyNames y DataKeys para tomar el id del producto que usarias de filtro

saludos

Alejandra Cecilia Eugenio Rivas dijo...

hola amigo disculpa que te moleste, es que quisiera que me ayudes con algo.
Tengo un gridview la cual esta lleno de registros de detalles que están vinculados con una cabecera, quiero generar una copia de todos los registros de detalles al momento de generar una modificación para bitacolizar esos registros y asi in activarlos y crear los nuevos registros como activos si me podrias ayudar con algun ejemplo o guiarme como hacerlo te lo agradecería mucho.

Leandro Tuttini dijo...

hola Alejandra

la verdad no se si entendi el planteo, pero si quieres realizar un duplicaod del registro podrias lograrlo directamente en la db creando un trigger

entonces cuando realizas un cambio en el registro el trigger en sql server este duplicaria el registro en otra tabla de historicos

saludos

Santiago ibarra ramirez dijo...

Hola leandro mira utilice tu ejemplo y en el GridView hijo tengo un button de selecciona pero nunca me dispara el evento ace el posback y nunca entra al evento que debesabes a que se debera de antemano muchas gracias.

Leandro Tuttini dijo...

hola Santiago

estas definiendo algun evento del gridview como ser el RowCommand, porque deberias definir en el boton o link un CommandName

como asocias el evento del boton a un evento en el codigo .net ?

saludos

Santiago ibarra ramirez dijo...

al final defini el evento onRowComman en el gridView padre padre por que el gridView hijo no me repeto ningun evento...
Muchas gracias Leandro...

Leandro Tuttini dijo...

hola Santiago

es que el evento deberia ir en el gridview hijo
por supuesto quizas debas utilizar el sender para saber que grid hijo lanza el evento

recuerda que si cargas el grid en el evento Page_Load ponerlo dentro del if que valida sino es PostBack

saludos

Gerardo Zarate Bustamante dijo...

Buenas tardes Leandro, implemente el ejemplo en una aplicacion y funciona perfecto. Uso una pagina maestra y en esta puse un updatepanel y su scriptmanager respectivo, al todo funciona de maravilla la primera vez pero la segunda que recarga la pagina el scrip ya no funciona o sea ya no expande para ver el detalle del grid, he estado buscando y lo que he encontrado es que hay que registrarla, he intentado en el load y en el rowdatabound pero no funciona ademas que al ser una funcion autoejecutable no tengo idea de como llamarla. ¿Podrias ayudarme a solucionar este detalle?
Gracias.

Leandro Tuttini dijo...

hola Gerardo

el tema es que al usar el UpdatePanel aunque no se actualice toda la pagina la seccion que este abarca si sufre un postback al servidor

por lo tanto a la vuelta de esta accion deberias volver a re-asignar las acciones de javascript o jquery que hayas definido

se que no es lo mismo pero analiza

[ASP.NET] PopUp Filtro – Usando jquery UI Dialog

veras como alli en el titulo " Re-asignación de evento jquery" sucede lo mismo que planteas

saludos

Sebastian Edgardo Kinderman Fuentealba dijo...

Hola Leandro, una consulta.
Tome tu ejemplo y le quise agregar la opción de poder seleccionar las filas, intente hacerlo en el evento rowDataBound con este código, pero me alego esto "Sólo se puede llamar a RegisterForEventValidation durante Render();"
este es el código:

e.Row.Attributes.Add("onclick", Page.ClientScript.GetPostBackClientHyperlink(gvOrders, "Select$" + e.Row.DataItemIndex, true));
e.Row.Style.Add("cursor", "pointer");

ahora como no funcione, a los GridViews les asigne la propiedad "AutoGenerateSelectButton = true"

esto funciona con el Grid padre, pero cuando quiero seleccionar una fila del Grid Hijo esta se oculta.

tienes alguna idea de que puede ser? o de que otra forma se podría hacer?

saludos

Leandro Tuttini dijo...

hola Sebastian

el tema es que se oculte viene porque al habilitar el AutoGenerateSelectButton este genera un postback al evento, lo cual aplica un render en la pagina, sin importar que este en un updatePanel ya que este tambien se actualiza

quizas debas usar invocaciones ajax usanndo jquery por medio de $.ajax a webmethods que definas en la pagina
de esta forma podrias realizar accion y aplicar javascript sin necesidad de eventos de .net, ojo no digo que los selectores que debas definir en jquery vayan a ser simples, pero creo que seria el mejor camino

saludos

Regner Leonardo Bernal Garnica dijo...

Leandro muchisimas gracias, el ejemplo es muy util, aunque me costo un poco adecuarlo a lo que tengo.. pero funciona...

sin embargo, en el gridview anidado necesito utilizar el metodo de edicion del gridview pero al hacerlo colapsa el gridview y luego no deja desplegarla nuevamente... y la verdad ya no se que hacer....

te agradezco si me puedes ayudar

mil gracias

Leandro Tuttini dijo...

hola Regner

la verdad mucho no se puede hacer, no si quieres usar evento de asp.net

quizas deberias usar eventos del lado del cliente usando jquery he invocar webmethods mediante $.ajax() para realizar las acciones sin que se actualice la pagina

de esta forma no perderias el estado del gridview y sus grid anidados

el updatepanel no aplica para este caso ya que sigue realizando postback y actualizando la seccion que define

saludos

Regner Leonardo Bernal Garnica dijo...

Leandro mil gracias por tu aclaracion.

Unknown dijo...

Hola Leandro espero no molestarte estoy en mis inicios de VB 2010 el problema es el siguiente tengo un DataGridView en visual Basic en 2010 traje los datos desde una tabla de MySql corre bien los datos se visualizan bien pero cuando doy un clic o doble clic en los titulos de la columna o en la fila me sale error como depurar esto, estas son las lineas de programación para corregir ese error
Private Sub DgVCategoria_CellDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DgVCategoria.CellDoubleClick
Dim row As DataGridViewRow = DgVCategoria.Rows(e.ColumnIndex)
TxtCodigo.Text = Convert.ToString(row.Cells("cod_categoria").Value)
TxtCategoria.Text = Convert.ToString(row.Cells("categoria").Value)

End Sub



cuando utilizo esto
Dim row As DataGridViewRow = DgVCategoria.Rows(e.ColumnIndex)
me sale error en las filas cuando doy doble clic en los titulos de las filas

cuando utilizo esto
Dim row As DataGridViewRow = DgVCategoria.Rows(e.RowIndex)
me sale error en la columnas cuando doy doble clic en los titulos de las columnas

te agradeceria muchisimo
espero haber sido claro en mi explicación

Gracias de antemano

Leandro Tuttini dijo...

hola Unknown

si presionas sobre el titulo se lanza la accion peor no hay una row o cell seleccionada
por lo que deberias al principio del codigo validarlo usando

If e.RowIndex = -1 Then
Return
End If

o sea si es -1 es porque no hay seleccion por lo que sales sin hacer nada

saludos

El Ferna dijo...

Hola Leandro una consulta, adapté tu código a VB2010 pero al momento de ejecutar el evento RowDataBound genera el siguiente error "referencia a objeto no establecida como instancia de un objeto", esto sucede en la linea en la que se hace el Ctype para el grid:
Dim gvDetails As GridView = CType(e.Row.FindControl("GridLicencias"), GridView)

Por favor sería de gran ayuda tu respuesta. Gracias de antemano.

Leandro Tuttini dijo...

hola El Ferna

ese error se produce porque no puede encontrar el grid que esta dentro del grid
sino puede encontrarlo entonces deja sin instanciar la busqueda y falla con ese mensaje

estas seguro que ubicas el grid de detalle de forma correcta?

saludos

Jocelyn F dijo...

Hola Leandro Buen dia
Quisiera si me pudieras orientar a hacer algo parecido a esto pero en visual studio 2010
Gracias

Leandro Tuttini dijo...

hola Jocelyn

es que no hay diferencia, la version de VS que utilices no afecta, se implementa de la misma forma

saludos

Unknown dijo...

Hola
He visto el link Tutorial 12...
http://msdn.microsoft.com/en-us/library/bb288032.aspx
y lo que quiero preguntarte es el grid hijo que sale, lo creas en diseño o mediante escribir codigo?
y si es en diseño como se hace?, no entiendo el Tutorial. Gracias de antemano

Leandro Tuttini dijo...

hola Unknown

la definicion del grid hijo se realiza desde html en la definicion del TemplateField

lo que se hace desde codigo es asignar los datos al grid

saludos

Unknown dijo...

Hola
Estoy modificando el ejemplo al conectar con otra base datos y me sale este mensaje
cuando intento ejecutar la aplicacion. Ahi va el ejemplo Gracias por la respuesta

Error de servidor en la aplicación '/'.

Error de compilación

Descripción: Error durante la compilación de un recurso requerido para dar servicio a esta solicitud. Revise los detalles de error específicos siguientes y modifique el código fuente en consecuencia.

Mensaje de error del compilador: CS1061: 'System.Web.UI.WebControls.GridView' no contiene una definición de 'IdCliente' ni se encontró ningún método de extensión 'IdCliente' que acepte un primer argumento de tipo 'System.Web.UI.WebControls.GridView' (¿falta una directiva using o una referencia de ensamblado?)

Error de código fuente:


Línea 12: $(function () {
Línea 13:
Línea 14: $('#<%=gvOrders.IdCliente %> img').click(function () {
Línea 15:
Línea 16: var img = $(this)

Leandro Tuttini dijo...

hola Unknown

como comente en la pregunta del foro debes usar:

$('#<%=gvOrders.ClientID%> img')

porques lo que buscas son las propiedades del gridview

saludos

Maicol8k dijo...

excelente ejemplo leandro tutini..
me sirvio mucho.. en verdad...
solo una pregunta mas..
se puede hacer un efecto al abrir y cerrar la vista de detalle?
me refiero a que se cierre mas lento
y se abra mas lento...
bueno gracias por todo

Leandro Tuttini dijo...

hola Maicol8k

si usas jquery podrias definir la accion de expandir y colpsar con efecto

Metodos para realizar animaciones estandar con libreria jquery


saludos

Maicol8k dijo...

una pregunta mas.. el gridviewdetalle puede colocarlo en en un mismo template con una imagen o label?


label
imagen
grilla

Alberto Barrera dijo...

Sirve correctamente solo que tengo un pequeño problema.
Al ponerlo dentro de un updatePanel
no realiza la funcion de click alguna solucion?????

Leandro Tuttini dijo...

hola Alberto

el tema es que no se lleva muy bien el updatepanel y jquery
intenta usar el on() en lugar de definir el click directamente
jquery on

saludos