domingo, 3 de enero de 2010

[DataGridView] Pasaje de información entre grids en distintos formulario

 

Introducción


Este artículo es consecuencia de otros descriptos con anterioridad

C# – Comunicar formularios de forma desacoplada

Como se habrá visto comunicar formularios de forma desacoplada puede no se tan simple alguna veces y es justamente cuando se hace uso de información entre grillas que la situación puede ser algo mas compleja

Este ejemplo intenta demostrar como realizar la comunicación y desde un formulario hijo pasar información de ítems seleccionados al un formulario padre o quien realiza la llamada.

 

Definición de la Interfaz


Para la comunicación eficiente de los formulario, se crearan un contrato que permitirá enlazarlos con el mínimo acoplamiento entre ellos.

interface IAddItem
{
    void AddNewItem(DataGridViewRow row);
}

Como se observa el método que tomara el retorno de la selección del ítem define un DataGridViewRow, o sea un registro completo seleccionado en la grilla del formulario hijo.

 

Formulario Padre


Como se observara el formulario padre que realizara la apertura debe implementar la interfaz IAddItem definida en el punto anterior.

 

public partial class Form1 : Form, IAddItem
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Form2 formAdd = new Form2();
        formAdd.Show(this);

    }

    #region IAddItem Members

    public void AddNewItem(DataGridViewRow row)
    {
        string item = row.Cells["item"].Value.ToString();
        string desc = row.Cells["Desc"].Value.ToString();

        this.dataGridView1.Rows.Add(new []{ item, desc }); 

    }

    #endregion


}

 

Es importante destacar algunas líneas:

- Línea 11: es el punto en donde se realiza la apertura del forma hijo, y es allí donde se le indica quien es el padre o quien esta realizando al apertura del formulario, esto se esta indicando al hacer uso del “this” en el parámetro del método Show()

- Líneas 17-24: en estas línea de código se estará tomando la fila que se retorna de la selección, se recupera cada valor y se arma el nuevo registro, en este punto en caso de que fuera necesario se podría realizar cálculos o modificar los datos, para ser luego insertados en la grilla de ítems seleccionados.

 

Formulario Hijo


Este formulario contiene la grilla con los ítems que pueden ser seleccionados, los cuales a modo de ejemplo fueron creados manualmente en un DataTable.

El punto clave aquí es el botón que envía el registro seleccionado, del datagridview del formulario hijo al formulario padre que realizo la llamada:

private void button1_Click(object sender, EventArgs e)
{
    DataGridViewRow row = this.dataGridView1.SelectedRows[0] as DataGridViewRow;


    IAddItem parent = this.Owner as IAddItem;
    parent.AddNewItem(row);

    this.Close();
}

Como se observa se toma la fila seleccionada, y acto seguido se llamada al método de la interfaz del formulario que realizo la llamada.

El parámetro “this” enviado en el método Show() es justamente la propiedad Owner del formulario hijo, y al implementar la interfaz este puede ser casteado a el tipo IAddItem sin problemas, para luego invocar al método que define.

 

[C#] 
[VB.NET] 

54 comentarios:

  1. Hola leandro, disculpa pero esto no tiene nada que ver con la entrada que hicistes, pero me gustaria saber que sitios puedo revisar para mantenerme actualizado y que blogs, ya que muchos blogs dejan de postear, los boletines de la microsoft me llegan siempre pero algo adicional. gracias

    ResponderEliminar
  2. Hola Leandro, soy un poco novato en el c# estuve siguiendo el ejemplo que de pasaje de iformacion y me salta un error en la linea parent.AddNewItem(row); del form hijo, dice "referencia a objeto no establecida como instacia de un objeto" desde ya muchas gracias estan geniales tus aportes

    ResponderEliminar
  3. hola alemar

    No se si habias podido descargar el ejemplo de codigo, ya que tuve problemas con skydrive, pero ahora esta publicado.

    Por el mensajes que describes me suena a que la variable parent esta tomando un valor nulo

    Cuando abres el form hijo tienes en cuenta de pasarle en el metodo Show() el valor this ?

    Form2 formAdd = new Form2();
    formAdd.Show(this);

    Como muestran estas lineas,
    esto es lo que hace disponible que el la propiedad Owner pueda usarse

    saludos

    ResponderEliminar
    Respuestas
    1. hola, funciona super bien tu ejemplo, pero tengo un problema no puedo implementar en un mdiparent, es decir agregar un row en un dgw en un mdi desde una form, lo intento y me abre un nuevo dgv .. gracias por la ayuda

      Eliminar
    2. hola
      Te abre un nuevo dgv? no sera que abre un nuevo form
      Recuerda que no debes usar el "new" para crear una instancia del form, sino que debes acceder a la instancia existente
      Debes pasar los datos usando la instancia existente, analiza esta otra tecnica
      Comunicar Formularios
      esta aplica en ambientes con o sin mdi
      saludos

      Eliminar
  4. Gracias Leo no pense que respondias tan rapido jeje, era lo que decias me faltaba el this y ya pude bajar el ejemplo muchas gracias.-

    ResponderEliminar
  5. hola me gustaria, saber como paso los datos seleccionados de un data grid a otro datagrid que esta en otro formulario . Se lo agradeceria que me ayudara.

    ResponderEliminar
  6. hola amarilis

    Imagino quieres pasar esta fila a un formulario hijo, o sea que estas abriendo ?

    Si es asi podrias usar el constructor de ese form que necesita recibir la row seleccionada, o sino propiedades.

    En este articulo explico el tema

    [WinForms] – Pasaje de información formulario hijo



    saludos

    ResponderEliminar
  7. Hola leandro esta muy bueno el tutorial pero la verdad si especificamente puedes decirmo como pasar los datos de la fila a la que diera doble click al otro datagridview en este caso del grid1 al grid2

    Leandro te agradeceria mucho la ayuda mi correo es harvy.vanegas@gamil.com

    ResponderEliminar
  8. hola Harvy

    la tecnica es la misma, solo que ne lugar de programar la accion en los botones usarias el evento

    CellDoubleClick

    recuerda que en este evento tienes el

    e.RowIndex, para poder reconocer en que fila se realizo ese doble clik

    detectado esto el resto es identico al del boton que implementa el articulo

    saludos

    ResponderEliminar
  9. Hola Leandro antes que nada gracias por la ayuda fijate que publique un nuevo tema en mi foro sobre esto es bastante parecido me gustaria que lo vieras y me des tu opinion.

    http://sonnysoft.foroes.net/t87-pasar-datos-de-un-datagridview-a-otro-datagridview-en-distentos-formularios-tutorial#98

    ResponderEliminar
  10. hola Harvy

    revise el articulo y puedo comentarte varios puntos

    - no veo que dejaras en ningun link el codigo con el ejemplo que has desarrollado, con una imagen de solo 3 lineas de codigo se puede apreciar muy poco la solucion. podrias usar skydrive para publicar el codigo

    - algo que no queda claro en el codigo es que seria "frmFacturacion", es la instancia , es la clase del formularios, que es ?
    porque para acceder a los controlas deberias pasar la instancia

    - ademas la idea que intento promover es que no se acople la comunicacion (imagino no era es la idea de tu articulo), se que no es tan directo como acceder como lo haces (tampoco era la idea que sea facil), pero si trae otras ventajas en cuanto a la mantenibilidad y la posibilidad de reutilizar el codigo

    saludos

    ResponderEliminar
  11. Bueno si Leandro tienes razón como que explico muy poco... De ser mi maestro de Programación ya me hubieses reprobado jeje... Con relación al skyDrive no lo sé usar o al menos nunca lo he probado.

    ResponderEliminar
  12. Hola Leandro antes que nada felicitarte por tu excelente tuto, mi problema sucede que al implementarlo en mi proyecto, me genera un error-->
    IAddItem parent = this.Owner as IAddItem;
    en esa parte de codigo, me genera una excepcion nula, revise el show(this) del formulario padre, por lo que al debuggear el owner si esta lleno, pero en si la sentencia completa(this.Owner as IAddItem) muestra null. Agradeceria tu ayuda.

    ResponderEliminar
  13. Ya lo revise y es por uso de un MDI container que tengo en mi proyecto, asi q probando agregue un Form3 a tu proyecto de tipo MDI que invoque al Form1 y me genera el mismo error, aun no se como solucionarlo.

    ResponderEliminar
  14. hola Jose

    pero la interfaz IAddItem es implementada por el form que invoca al hijo ?

    recuera que el forma deberia definir esta en su declaracion

    public class Form3 : Form, IAddItem {
    }

    es importante que la implemente sino al castear seguro sera null

    saludos

    ResponderEliminar
  15. Hola, bueno si la interfaz esta en mi formulario padre, pero para que me entiendas mejor, no se si pudieses crear a tu proyecto un Form3 q sea mdi y que llame al form1, te saldra la misma excepcion que a mi, ahora veo que el owner lo toma al mdi(form3) y no al padre(form1), si me pudieses ayudar, saludos y gracias.

    ResponderEliminar
  16. hola Jose

    pero si estas trabajando en un ambiente mdi el owner no aplica, no puedes usarlo, como explico aqui

    Comunicar formularios MDI


    saludos

    ResponderEliminar
  17. Bueno no se si lo mío tenga que ver con éste tema pero bueno, mi problema es que quiero pasar los datos de una columna de un datagridview a una columna d otro datagridview que está en otro formulario, el ingreso de datos lo hago por medio de calculos matemáticos, es decir que no utilizo ninguna conexión con BD... Estoy tratando de realizar una prueba de chi-cuadrado... Ayudenme a resolver mi problemas por favor... Éste s mi correo tooplay21@hotmail.com...

    PD: Es de urgencia

    ResponderEliminar
  18. hola tooplay21

    pero este otro formulario al cual quieres pasarle la informacion es un form hijo ? o sea desde el form donde tienes el grid es el form padre y abres otro form al cual le pasas la info

    si es asi recuerda que puedes usar el constructor o propiedades del form hijo para asignar la informacion

    [WinForms] – Pasaje de información formulario hijo

    de esta forma es que pasarias una lista de datos que necesitas en el otro formulario

    saludos

    ResponderEliminar
  19. hola leandro primero te felicito por tu blog me ayudo bastante pero me di cuenta que en tu ejemplo solo pasar una fila en distintos formularios mi pregunta es si se pueden pasar varias filas a la vez osea dos registro? me podrias mostrar un ejemplo de como pasar varios registro

    gracias y saludos

    ResponderEliminar
  20. hola Ascencio

    claro porque no
    solo sera cuestion de usar un List<> del objeto que quieras pasar de un form a otro

    la lista permitira pasar uno o mas objetos

    saludos

    ResponderEliminar
  21. hola leandro

    muchas gracias por el dato solo tengo una duda el list va en la interface o en el boton donde agrega los campos

    gracias y saludos

    ResponderEliminar
  22. hola Ascencio

    en ambos, lo usas para definir el metodo o propiedad de intercambio pore so debe ir en el interfaz

    pero tambien lo usarias cuando implementas la interfaz en la clase concreta

    saludos

    ResponderEliminar
  23. hola leandro me podrias enviar un ejemplo de como hacerlo mi correo es angel_aspe@hotmail.com

    gracias y saludos

    ResponderEliminar
  24. hola Ascencio

    la verdad no tengo armado nada parecido, pero no veo que sea complicado
    digo si sabes insertar y rrecuperar registros en tu db solo es cuestion de poner dosc campos de coordenadas para guardar la posicion de cada control que se cree dinamicamente

    y luego recuperarlo y usar

    int x= Convert.ToInt(row["X"]);
    int y= Convert.ToInt(row["Y"]);

    Label lbl1 = new Label();
    lbl1.Localtion = new Point(x, y);

    donde use row sera el Datarow de un datatable que usarias para recuperar la info de la tabla

    saludos

    ResponderEliminar
  25. Increible Leandro, gracias por todos tus aportes....
    Tengo una duda y ojala me puedas ayudar; sucede que desde un form padre abro un hijo (el padre no se cierra, siempre esta abierto) al estar en el form hijo selecciono (doble click) una fila de un datagridview y cierro el form hijo, pero al estar nuevamente en el form padre no me muestra la fila seleccionada del form hijo, que ya esta cerrado. Gracias de antemano...

    ResponderEliminar
  26. hola abel_c_b

    analzia el codigo del boton "buscar" de este articulo

    [N-Tier] – Desarrollo en capas - Ejemplo Facturación – Parte 1

    creo que es la funcionalidad que describes

    recuerda que al form hijo desde el padre debes acceder con la instancia del form, puedes poner breakpoint en el codigo para inspeccionar el estado de las variables

    saludos

    ResponderEliminar
  27. Hola leandro

    primero queria felicitarte y agradacerte por las aportaciones de tu blog

    soy algo nuevo en programacion y queria ver si podrias orientarme un poco

    tengo un proyecto con varias formas (cada una con un datagrid) y estas interactuan con una bd en sql 2005, ademas tambien tengo varias clases

    en una clase (llamada conexion) tengo definida la conexion, al dar click en un boton(por ejemplo alta) mando a llamdar una fucion de esa clase, le mando un string(en ese string tengo definido el query) la funcion recibe el string y hace la consulta

    la idea es que en esa clase definir una funcion, y desde la forma mandarla a llamar para que haga una consulta(en ese caso un select) y la informacion la llene en el datagrid de la forma, solo que ando un poquito trabado en eso

    ese es mi problema espero y pudieras orientarme
    gracias de antemano. saludos

    ResponderEliminar
  28. Hola leandro..qisiera saber como hago para dar doble click en una fila del grid view y asi abrir otro form pasando los valores de una columna sin utilizar el evento gridviewslectedchanging solo dando doble click a una fila determinada

    ResponderEliminar
  29. hola daniel

    pero tu aplicacion es web o winforms ? o sea usas el datagridview o el gridview

    si la aplicacion es winforms podrias usar el evento

    DataGridView.CellDoubleClick Event

    saludos

    ResponderEliminar
  30. hola bto

    no recomendaria tomes ese camino de crear una clase que reciba la query, porque seguramente lo diseñaras de forma incorrecta no soportando el uso de parametros

    mejor si diseñas desarollando en capas

    [N-Tier] – Desarrollo en capas - Ejemplo Facturación – Parte 3

    como veras la capa de datos define la conexion y realiza la query pero orientada al negocio, la conexion la defines en el archivo de configuracion

    saludos

    ResponderEliminar
  31. Comprendí completamente como utilizar la interfaz y pasar los registros. Tengo duda de algunas líneas de código. Como por ejemplo:
    string item = row.Cells["item"].Value.ToString();
    ¿Eso quiere decir que si el valor que el form hijo me va a pasar es de tipo int me causará problemas?

    Otro es el datatable. ¿Que sucede cuando los datos que deseo pasar provienen de una base de datos?
    Mi implementación la estoy realizando en 3 capas. Ya vi tus ejemplos y son realmente complicados a pesar de la explicación que das.

    Saludos.

    ResponderEliminar
  32. hola WilO Frias

    en realidad esa conversion a string se realiza porque simplemente se espera un texto, pero si sabes que es un valor numerico puedes convertirlo sin problema

    lo que si recomendaria es que uses el int.TryParse() para poder convertir sin que se produzca un exception si es que no puede lograrlo

    que los datos vengan de la base de datos no deberia afectar en nada, ya questo de comunicar formulario se da en la presentacion, despues si la opcion vieno de una query a la db o si lo asignaste por otro medio es indistinto no deberia afectar al resto de las capas como comunicas la parte visual

    saludos

    ResponderEliminar
  33. Hola Leandro buenas noches, tu ejemplo me sirvio bastante, te lo agradesco, pero me surgio una duda, si tengo un datagridview con un DataGridViewCheckBoxColumn y quiero pasar varios registros al a vez, como seria.
    Gracias

    ResponderEliminar
  34. hola Jonathan

    no entendi como un combo en el grid afectaria la info que enviarias

    se supone que el combo solo toma un unico dato seleccionado

    igualmente podrias definir en el constructor o propiedad una List<> para pasar varios items

    saludos

    ResponderEliminar
  35. hola leandro, gracias por responder, yo me referia a una columnas de ChekBox para seleccionar multiples filas para luego pasarlos a otro datagridview de otro formulario.

    Aunque me haz dado la solucion: "definir en el constructor o propiedad una List<> para pasar varios items".

    Gracias,

    ResponderEliminar
  36. hola

    ahh era una columna checkbox habia leido mal el tipo de columan a la cual hacias referencia

    igualmente la respuesta seria la misma usa un List<> para pasar las filas seleccionadas

    saludos

    ResponderEliminar
  37. En el supuesto caso cuando ya tenemos herencia ,por ej. en mis forms heredan de DotNetBar de unas plantillas de office 2007, en este caso no es posible realizar tu ejemplo,no? porque lei que en c# o vb no viene la posibilidad de herencia multiple, en dicho caso solo es posible el pasaje entre distintos datagridview en distintos
    forms por ej. definiendo variables globales o publicas en el form que va a recibir el dato y en donde se manda los datos indicar columna x columna de una fila el valor que tiene el datagridview que quiero mover el dato?

    ResponderEliminar
  38. hola Andres

    no veo que relacion tiene la herencia multiple con el hecho de pasar datos entre formularios

    hay otras tecnicas ademas de definir variables globales que se pueden utilizar para pasar datos entre forms

    en este articulo explico una que podrias utilizar, que sea un datagridview o algun grid de terceros la tecnica seria la misma, quizas cambie el tipo de datos

    pero no se necesite de ninguna herencia para esto

    saludos

    ResponderEliminar
  39. Buenas Leandro, tengo un problema... Esto podría aplicarse a un datagridview del form padre enlazado a datos? Es que me esta dando problemas.
    Si es así como tendria que ser?

    ResponderEliminar
  40. hola Mikel

    si podrias aplicarlo, aunque quizas tambien deberias analizar

    [DataGridView] – Pasar Registros entre Grillas


    porque si el grid esta enlazado a datos deberias asignar el nuevo item en los datos del grid tiene asinado al datasource

    saludos

    ResponderEliminar
  41. buen dia amigos: tengo una super pregunta tengo un formulario (agenda) en el pongo un numero y una descripcion,(los mando a guardar en una tabla (agenda)con los siguientes campos numero, texto,tratado) luego mando a llamar esos datos de mi base en otro formulario (puntos tratados) donde tengo un campo que se llama tratado ese campo esta definido como boolean lo que quiero hacer es seleccionar ese CheckBox y decir de la agenda ese punto fue tratado en la reunion y guardarlo en mi tabla agenda ojala puedas ayudarme. gracias!!! 

    ResponderEliminar
  42. hola Marco

    cuando creas el registro en agenda que vlaor pones en el campo tratado ? le pones false

    si tienes un valor bool que recuperas de la db simplemente podrias hacer

    chkTratado.Checked = Convert.ToBoolean(reader["tratado"]);

    con esto asignas la marca o no segun el vlaor que tenga en la tabla
    "reader" es un Datareader, pero se podria hacer para un DataTable de forma similar

    saludos

    ResponderEliminar
  43. Hola Leandro antes que nada muchas gracias por ayudarnos con este aporte tuyo, ahora lo estoy siguiendo, pero el link de skydrive esta caido, no se si pudieras ayudarme volviendolo a subir. De antemano gracias

    ResponderEliminar
  44. Buen día. Gracias por el tutorial. Una consulta si no es mucha molestia. Como le hago para evitar que se envie el mismo registo(articulo) a el formulario padre. Es decir si ya se envio una vez, evitar que se vuelva a enviar.

    Espero me puedas orientar con esta duda.

    Saludos

    ResponderEliminar
    Respuestas
    1. hola frank

      Podrias validarlo, o sea deja que el usuario seleccione el item que quiera pero al enviarlo al otro form revisas si ese dato ya existe
      Si ya esta presente le informas mediante un mensaje y no lo agregas
      Podrias evitar cerrar el form hijo si es que se da este caso, el metodo que implementas en la interface devuelva un bool indicando si lo agrego o no

      saludos

      Eliminar
    2. Hola Leandro. Buen dia

      He estado buscando y encontre esta funcion para buscar si ya escite el dato dentro del datagridview del form padre.

      #Region "IAddItem Members"
      Public Function AddNewItem(ByVal row As DataGridViewRow) As Boolean Implements IAddItem.AddNewItem
      If Not ExisteEndgv(True) Then
      Dim Producto As String = row.Cells("columnId").Value.ToString()
      Dim Descripcion As String = row.Cells("columnDescripcion").Value.ToString()
      Dim Precio As Decimal = row.Cells("ColumnPrecio").Value.ToString()
      Me.DataGridView1.Rows.Add(New String() {Producto, Descripcion, Precio})
      Return True
      End If
      Return False
      End Function
      #End Region

      Private Function ExisteEndgv(ByVal producto As String) As Boolean
      Dim existe As Boolean = False
      For Each fila As DataGridViewRow In DataGridView1.Rows
      Dim verificar As String = Convert.ToString(fila.Cells("CProducto").Value)
      If producto = verificar Then
      existe = True
      End If
      Next
      Return existe
      End Function

      La interfaz la tengo asi

      Interface IAddItem
      Function AddNewItem(ByVal row As DataGridViewRow) As Boolean
      End Interface

      Lo que nose es como hacerle para llamar a la funcion dentro del form hijo

      Private Sub dgvDatos_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgvDatos.CellDoubleClick
      Try
      Dim row As DataGridViewRow = TryCast(Me.dgvDatos.SelectedRows(0), DataGridViewRow)
      Dim parent As IAddItem = TryCast(Me.Owner, IAddItem)
      parent.AddNewItem(row)
      Me.Close()
      Catch ex As Exception
      MessageBox.Show(String.Format("Error : {0}", ex.Message), "Error Inesperado", MessageBoxButtons.OK, MessageBoxIcon.Error)
      End Try
      End Sub

      Eliminar
    3. hola

      lo primcipal aqui es como abres el form hijo, alli veo que usas el owner por lo que deberia ser

      FormHijo frm = new FormHijo();
      frm.Show(this);


      ese this que uso en el show es quien asigna la instancia del form padre que implementa la interfaz, asi es como tendras el owner para poder castear a la interface, pudiendo invocar el metodo que expone

      saludos

      Eliminar
  45. tengo 4 formulario , uno de ellos es MDI, Y los otros son hijo, en el primer formulario tengo que ingresar datos al data grid y almacenarlos temporal y NO utilizar base de datos.
    MDI: tiene menu strip: catalogo y seleccion del produto. y tambien toolstrip :agregar,facturar y buscar.

    LUEGO
    al dar clic al formulario seleccionar prod, me abre el formulario dentro de este tengo otro data grid y un texbox de buscar,,, solo que ingreso el nombre de la marca que deseo buscar ; pero tengo que dar clic al boton de busqueda del datagrid. y asi hace el proceso de busqueda.

    luego tengo que enviar estos datos a la de factura ya con su importe total , que tambien es un data grid.

    ResponderEliminar
    Respuestas
    1. hola
      pero cual seria el problema ? solo planteas la situacion de como los forms se abren

      Si el problema es que son form MDI puede resolverlo aplicado esta tecnica
      Comunicar Formularios

      saludos

      Eliminar
  46. Este blog a estas alturas esta salvando mi semestre gracias por el aporte

    ResponderEliminar
  47. Hola Leandro soy nuevo en la programacion de vb.net y estoy actualizando un programa hecho en vb6 a vb.net.
    Tengo mi formulario "Productos" en el cual medante un boton me abre otro form (ListaProductos) en este form unicamente esta un datagridview de 5 columnas que muestra todos los productos existentes y algunas propiedades y un boton de aceptar.
    como le hago para que al momento de seleccionar una linea del DGV y oprimir el boton de aceptar se me cierre el form ListaProductos y el campo de "nombre"(columna 2) se pase al txtBuscar que tengo en el form de Productos y se active el metodo click del boton Buscar.
    estas son las lineas que quiero generar en vb.net

    ListaProductosForm
    Private Sub btnAceptar_Click()
    ProductosForm.txtBuscar.text = Trim(GridList.selectedItem.SubItems(1))
    ProductosForm.btnBuscar_Click
    Unload ListaProductosForm

    ResponderEliminar
    Respuestas
    1. Hola

      Podrias aplicar la tecnica de este articulo

      Comunicar Formularios

      como veras defines una interfaz para que desde el form del grid puedas pasar datos a la instancia del forma padre

      saludos

      Eliminar