domingo, 1 de diciembre de 2013

Pasar datos de un DataGridView a otro DataGridView ubicados en Forms diferentes

Hola a todos:

Motivado por uno de los usuarios del Foro de C# me tomo unos minutos parar mostrar como podemos fácilmente enviar valores de un DataGridView a otro DataGridView ubicado en un formulario diferente.
Como siempre pondré el código tanto para C# como para Vb.Net, y tratare de ser los mas explicito posible, si después de leer el articulo, descargar el proyecto de ejemplo y analizar su contenido usted no logra implementarlo, sírvase de hacer las consultas que crea necesarias proporcionando la mayor cantidad de información de su caso.

Recuerde que el objetivo del articulo no es otro mas que el de proporcionar una guía para lo Párvulos en .Net y que solo es una opción para la solución de un problema, recordando que un problema tiene muchas posibles soluciones.

Recuerde que al final de Articulo podrá encontrar los proyectos de ejemplo descargables tanto para C# y Vb.Net.

Entrando en contexto…

Crearemos un proyecto que simulara la carga de artículos de un Formulario a otro Formulario utilizando controles DataGridView para mostrar los datos.
  1. El proyecto arrancara con el Form1 como principal
  2. Al presionar el botón “Agregar” se mostrara el Form2 con un control DataGridView cargado con datos
  3. Al hacer doble Click sobre algún row del DataGridView del Form2 automáticamente se enviara la información contenida en sus celdas al DataGridView del form1, mostrándose también en los controles TextBox.
  4. El proceso antes de agregar el nuevo Row al DataGridView hará una validación sobre los datos ya agregados para descartar que este articulo no se encuentre ya en la lista, de ser así lanzara una mensaje de informando de la situación y no agregara el row, en caso contrario el row será agregado sin problemas.
Dicho todo lo anterior, procedamos a crear nuestro proyecto de ejemplo.
  1. Cree un proyecto del tipo WindowsForms
  2. Automáticamente le creo un formulario llamado Form1, dejemos el nombre de los controles por defecto para no complicarnos la vida nombrándolos en estos momentos, aunque recalco que en proyecto reales el nombre de los controles es vital.
  3. Agregue 4 controles labels y establezca en la propiedad Text, Número, Nombre, Precio y Cantidad respectivamente
  4. Agregue 4 controles TextBox
  5. Agregue un control Button y establezca en la propiedad Text, Cargar.
  6. Agregue un control DataGridView, agregue 4 columnas, establezca la propiedad SelectionMode en FullRowSelect, AllowUserToAddRows, AllowUserToDeleteRows en false
Su diseño podría ser similar a este:
frm1

Ahora, en el Form dos inserte un control DataGridView similar al que acaba de crear en el Form1, para optimizar el tiempo puede copiar y pegar el control del Form1, el diseño que se espera obtenga es similar a este:
frm2
Bien, una vez que tengamos el tema del diseño de nuestros Forms resueltos, procedamos a meter código.
Inserte una nueva clase a su proyecto y llámela EProducto, la clase tendrá una estructura como esta:
C# :
using System;

namespace DataGridViewsendRow
{
    public class EProducto
    {
        //Estas son propiedades Autoimplementadas y su uso requiere
        // del Framework 4.0 Client Profile como mínimo
        public int Numero { get; set; }
        public string Nombre { get; set; }
        public Decimal Precio { get; set; }
        public Decimal Cantidad { get; set; }
    }
}

Vb.Net :
Public Class EProducto
    'Estas son propiedades Autoimplementadas y su uso requiere
    'del Framework 4.0 Client Profile como mínimo
    Public Property Numero() As Integer
    Public Property Nombre() As String
    Public Property Precio() As Decimal
    Public Property Cantidad() As Decimal
End Class

Agregue una nueva clase y llámela IProducto, esta clase contendrá una interfaz que será el puente de comunicación entre ambos Forms, este es el Core de nuestro proyecto y ejemplo.

Dentro de la clase cree la siguiente estructura de código:

C# :
namespace DataGridViewsendRow
{
    //Nombre de la interfaz
    public interface IProducto
    {
        bool LoadDataRow(EProducto producto);
    }
}

Vb.Net :
'Nombre de la interfazPublic Interface IProducto
    Function LoadDataRow(producto As EProducto) As Boolean
End Interface

Esta es la estructura completa de código que necesitara para recibir los datos en el Form1:

C# :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace DataGridViewsendRow
{
    //
    //Heredamos la Interfaz IProducto, recuerde que este será nuestro puente de comunicación entre ambos Forms
    public partial class Form1 : Form, IProducto
    {
        //
        //Creamos una lista del tipo Eproducto, que será la encargada de
        //recibir la información del Form2 y almacenarla, posteriormente servirá
        //de fuente de datos para el DataGridView
        private static readonly List<EProducto> Products = new List<EProducto>();

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //
            //Instanciamos el Form2
            Form2 frm = new Form2();
            //
            //Le indicamos quien lo mando a llamar usando la Propiedad Caller
            frm.Caller = this;
            //
            //Mostramos el Form2
            frm.ShowDialog();
        }

        /// <summary>
        /// Funcion encargada de agregar un nuevo Item a la lista siempre y cuando no exista
        /// </summary>
        /// <param name="product">instancia de la clase Eproduct</param>
        /// <returns>Si el Item fue agregado a la lista devuelve True si no fue agregado retorna False</returns>
        public bool LoadDataRow(EProducto product)
        {
            //Busca si el Articulo ya se encuentra en la lista
            bool exists = Products.Any(x => x.Numero.Equals(product.Numero));
            //
            //
            //Preguntamos por el resultado de la búsqueda del Articulo dentro de la lista
            if (!exists)
            {
                //
                //Si el articulo no existe dentro de la lista Mapeamos el item de la entidad Eproducto 
                //a los TextBox
                textBox1.Text = Convert.ToString(product.Numero);
                textBox2.Text = product.Nombre;
                textBox3.Text = Convert.ToString(product.Precio);
                textBox4.Text = Convert.ToString(product.Cantidad);
                //
                //Agregamos a la lista de productos el Item enviado por el Form2
                //
                Products.Add(product);
                //
                //
                //
                dataGridView1.AutoGenerateColumns = false;
                //
                //
                dataGridView1.DataSource = null;
                //
                //Establecemos el DataSource del DataGridView enlazándolo a la lista
                //genérica
                dataGridView1.DataSource = Products;
                //
                //Mapeamos las propiedades a las columnas
                dataGridView1.Columns["ColumnNumero"].DataPropertyName = "Numero";
                dataGridView1.Columns["ColumnNombre"].DataPropertyName = "Nombre";
                dataGridView1.Columns["ColumnPrecio"].DataPropertyName = "Precio";
                dataGridView1.Columns["ColumnCantidad"].DataPropertyName = "Cantidad";

                //
                //Retornamos True
                return true;
            }
            //
            //Si la condición exists es igual a False, es decir, que el producto SI existe en la lista
            //retornamos FALSE para mostrar un mensaje información
            return false;
        }
    }
}

Vb.Net :
Public Class Form1
    '
    'Heredamos la Interfaz IProducto, recuerde que este será nuestro puente de comunicación entre ambos Forms
    Implements IProducto

    'Creamos una lista del tipo Eproducto, que será la encargada de
    'recibir la información del Form2 y almacenarla, posteriormente servirá
    'de fuente de datos para el DataGridView
    Private Shared ReadOnly Products As New List(Of EProducto)()

    Private Sub button1_Click(sender As System.Object, e As System.EventArgs) Handles button1.Click
        '
        'Instanciamos el Form2
        Dim frm As New Form2()
        '
        'Le indicamos quien lo mando a llamar usando la Propiedad Caller
        frm.Caller = Me
        '
        'Mostramos el Form2
        frm.ShowDialog()
    End Sub

    ''' <summary>
    ''' Funcion encargada de agregar un nuevo Item a la lista siempre y cuando no exista
    ''' </summary>
    ''' <param name="product">instancia de la clase Eproduct</param>
    ''' <returns>Si el Item fue agregado a la lista devuelve True si no fue agregado retorna False</returns>
    Public Function LoadDataRow(product As EProducto) As Boolean Implements IProducto.LoadDataRow

        'Busca si el Articulo ya se encuentra en la lista
        Dim exists As Boolean = Products.Any(Function(x) x.Numero.Equals(product.Numero))
        '
        '
        'Preguntamos por el resultado de la búsqueda del Articulo dentro de la lista
        If Not exists Then
            '
            'Si el articulo no existe dentro de la lista Mapeamos el item de la entidad Eproducto 
            'a los TextBox
            textBox1.Text = Convert.ToString(product.Numero)
            textBox2.Text = product.Nombre
            textBox3.Text = Convert.ToString(product.Precio)
            textBox4.Text = Convert.ToString(product.Cantidad)
            '
            'Agregamos a la lista de productos el Item enviado por el Form2
            '
            Products.Add(product)
            '
            '
            '
            dataGridView1.AutoGenerateColumns = False
            '
            '
            dataGridView1.DataSource = Nothing
            '
            'Establecemos el DataSource del DataGridView enlazándolo a la lista
            'genérica
            dataGridView1.DataSource = Products
            '
            'Mapeamos las propiedades a las columnas
            dataGridView1.Columns("ColumnNumero").DataPropertyName = "Numero"
            dataGridView1.Columns("ColumnNombre").DataPropertyName = "Nombre"
            dataGridView1.Columns("ColumnPrecio").DataPropertyName = "Precio"
            dataGridView1.Columns("ColumnCantidad").DataPropertyName = "Cantidad"

            '
            'Retornamos True
            Return True
        End If
        '
        'Si la condición exists es igual a False, es decir, que el producto SI existe en la lista
        'retornamos FALSE para mostrar un mensaje información
        Return False
    End Function
End Class

Bien, ya tenemos la codificación del Form1, recuerde que este es el que hereda de la Interfaz, ahora vayamos a ver la codificación del Form2 encargado de enviar los datos del Row seleccionado:

C# :
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace DataGridViewsendRow
{
    public partial class Form2 : Form
    {
        //
        //Creamos una instancia de la interfaz IProducto para establecer el formulario llamador
        public IProducto Caller { private get; set; }

        public Form2()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Funcion encargada de devolver una lista de la Entidad EProducto cargada con datos
        /// </summary>
        /// <returns>Lista genérica de Eproucto</returns>
        private static List<EProducto> Products()
        {
            //Creamos la lista de Eproducto
            //
            List<EProducto> products = new List<EProducto>();

            //
            //Instanciamos la clase EProducto para establecerle datos
            //
            EProducto item1 = new EProducto()
            {
                Numero = 1,
                Nombre = "Nombre del producto 1",
                Precio = new decimal(5.5),
                Cantidad = new decimal(6.3)
            };
            EProducto item2 = new EProducto()
            {
                Numero = 2,
                Nombre = "Nombre del producto 2",
                Precio = new decimal(15.5),
                Cantidad = new decimal(2)
            };
            EProducto item3 = new EProducto()
            {
                Numero = 3,
                Nombre = "Nombre del producto 3",
                Precio = new decimal(25),
                Cantidad = new decimal(5)
            };
            EProducto item4 = new EProducto()
            {
                Numero = 4,
                Nombre = "Nombre del producto 4",
                Precio = new decimal(150.5),
                Cantidad = new decimal(12)
            };
            EProducto item5 = new EProducto()
            {
                Numero = 5,
                Nombre = "Nombre del producto 5",
                Precio = new decimal(4.5),
                Cantidad = new decimal(3)
            };
            EProducto item6 = new EProducto()
            {
                Numero = 6,
                Nombre = "Nombre del producto 6",
                Precio = new decimal(5),
                Cantidad = new decimal(6)
            };
            //
            //Agregamos las instancias con datos de Eproducto a la lista del mismo tipo
            //
            products.Add(item1);
            products.Add(item2);
            products.Add(item3);
            products.Add(item4);
            products.Add(item5);
            products.Add(item6);

            //
            //Devolvemos la lista
            //
            return products;
        }

        /// <summary>
        /// Método encargado de poblar el DatagridView con datos de una lista genérica, en este caso
        /// la devuelta por la función Products() creada previamente,
        /// </summary>
        private void FillDgv()
        {
            //Evitamos generar nuevas columnas a la izquierda de las que creamos en tiempo de diseño
            //
            dataGridView1.AutoGenerateColumns = false;
            //
            //Establecemos la fuente de datos, observe que únicamente mandamos a llamar a la función
            dataGridView1.DataSource = Products();
            //
            //Mapeamos las propiedades de la clase Eproducto devuelta por la función
            //Products() a las columnas del DataGridView
            //
            dataGridView1.Columns["ColumnNumero"].DataPropertyName = "Numero";
            dataGridView1.Columns["ColumnNombre"].DataPropertyName = "Nombre";
            dataGridView1.Columns["ColumnPrecio"].DataPropertyName = "Precio";
            dataGridView1.Columns["ColumnCantidad"].DataPropertyName = "Cantidad";

        }

        private void Form2_Load(object sender, EventArgs e)
        {
            //
             //Usamos el evento Load del Form2 para mostrar el DataGridView con datos
            FillDgv();
        }

        private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                //
                //Si el row en el que hicimos doble click es el encabezado del DataGridView, nos retornamos.
                if (e.RowIndex == -1)
                    return;

                //
                //Obtenemos el row en el cual se hizo doble Click
                //
                DataGridViewRow row = dataGridView1.Rows[e.RowIndex];

                //Instanciamos la clase Eproducto para cargar los datos tomándolos de las celdas del row
                EProducto item = new EProducto
                {
                    //
                    //Recuerde convertir al tipo de dato correcto
                    //
                    Numero = Convert.ToInt32(row.Cells["ColumnNumero"].Value),
                    Nombre = Convert.ToString(row.Cells["ColumnNombre"].Value),
                    Precio = Convert.ToDecimal(row.Cells["ColumnPrecio"].Value),
                    Cantidad = Convert.ToDecimal(row.Cells["ColumnCantidad"].Value)
                };

                //
                //Si no existe llamador para nuestro formulario nos retornamos sin hacer ninguna acción
                //
                if (Caller == null)
                    return;

                //Si el Form1 devolvió false por haber encontrado el Producto dentro de la lista
                //Informamos de lo sucedido al usuario
                if (!Caller.LoadDataRow(item))
                {
                    MessageBox.Show("El Producto ya existe en la lista", "Atención", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("Error : {0}", ex.Message), "Error Inesperado", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
}

Vb.Net :
Public Class Form2
    '
    'Creamos una instancia de la interfaz IProducto para establecer el formulario llamador
    Public Property Caller() As IProducto


    ''' <summary>
    ''' Función encargada de devolver una lista de la Entidad EProducto cargada con datos
    ''' </summary>
    ''' <returns>Lista genérica de Eproucto</returns>
    Private Shared Function Products() As List(Of EProducto)
        'Creamos la lista de Eproducto
        '
        Dim _products As New List(Of EProducto)()

        '
        'Instanciamos la clase EProducto para establecerle datos
        '
        Dim item1 As New EProducto()
        item1.Numero = 1
        item1.Nombre = "Nombre del producto 1"
        item1.Precio = New Decimal(5.5)
        item1.Cantidad = New Decimal(6.3)

        Dim item2 As New EProducto()
        item2.Numero = 2
        item2.Nombre = "Nombre del producto 2"
        item2.Precio = New Decimal(15.5)
        item2.Cantidad = New Decimal(2)

        Dim item3 As New EProducto()
        item3.Numero = 3
        item3.Nombre = "Nombre del producto 3"
        item3.Precio = New Decimal(25)
        item3.Cantidad = New Decimal(5)

        Dim item4 As New EProducto()
        item4.Numero = 4
        item4.Nombre = "Nombre del producto 4"
        item4.Precio = New Decimal(150.5)
        item4.Cantidad = New Decimal(12)

        Dim item5 As New EProducto()
        item5.Numero = 5
        item5.Nombre = "Nombre del producto 5"
        item5.Precio = New Decimal(4.5)
        item5.Cantidad = New Decimal(3)

        Dim item6 As New EProducto()
        item6.Numero = 6
        item6.Nombre = "Nombre del producto 6"
        item6.Precio = New Decimal(5)
        item6.Cantidad = New Decimal(6)

        '
        'Agregamos las instancias con datos de Eproducto a la lista del mismo tipo
        '
        _products.Add(item1)
        _products.Add(item2)
        _products.Add(item3)
        _products.Add(item4)
        _products.Add(item5)
        _products.Add(item6)

        '
        'Devolvemos la lista
        '
        Return _products
    End Function

    ''' <summary>
    ''' Método encargado de poblar el DatagridView con datos de una lista genérica, en este caso
    ''' la devuelta por la función Products() creada previamente,
    ''' </summary>
    Private Sub FillDgv()
        'Evitamos generar nuevas columnas a la izquierda de las que creamos en tiempo de diseño
        '
        dataGridView1.AutoGenerateColumns = False
        '
        'Establecemos la fuente de datos, observe que únicamente mandamos a llamar a la función
        dataGridView1.DataSource = Products()
        '
        'Mapeamos las propiedades de la clase Eproducto devuelta por la función
        'Products() a las columnas del DataGridView
        '
        dataGridView1.Columns("ColumnNumero").DataPropertyName = "Numero"
        dataGridView1.Columns("ColumnNombre").DataPropertyName = "Nombre"
        dataGridView1.Columns("ColumnPrecio").DataPropertyName = "Precio"
        dataGridView1.Columns("ColumnCantidad").DataPropertyName = "Cantidad"

    End Sub

    Private Sub Form2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        FillDgv()
    End Sub

    Private Sub dataGridView1_CellDoubleClick(sender As System.Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dataGridView1.CellDoubleClick
        Try
            '
            'Si el row en el que hicimos doble click es el encabezado del DataGridView, nos retornamos.
            If e.RowIndex = -1 Then
                Return
            End If

            '
            'Obtenemos el row en el cual se hizo doble Click
            '
            Dim row As DataGridViewRow = dataGridView1.Rows(e.RowIndex)

            'Instanciamos la clase Eproducto para cargar los datos tomándolos de las celdas del row
            '
            'Recuerde convertir al tipo de dato correcto
            '
            Dim item As New EProducto()
            item.Numero = Convert.ToInt32(row.Cells("ColumnNumero").Value)
            item.Nombre = Convert.ToString(row.Cells("ColumnNombre").Value)
            item.Precio = Convert.ToDecimal(row.Cells("ColumnPrecio").Value)
            item.Cantidad = Convert.ToDecimal(row.Cells("ColumnCantidad").Value)

            '
            'Si no existe llamador para nuestro formulario nos retornamos sin hacer ninguna acción
            '
            If Caller Is Nothing Then
                Return
            End If

            'Si el Form1 devolvió false por haber encontrado el Producto dentro de la lista
            'Informamos de lo sucedido al usuario
            If Not Caller.LoadDataRow(item) Then
                MessageBox.Show("El Producto ya existe en la lista", "Atención", MessageBoxButtons.OK, MessageBoxIcon.[Stop])
            End If
        Catch ex As Exception
            MessageBox.Show(String.Format("Error : {0}", ex.Message), "Error Inesperado", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

    End Sub
End Class

Hasta este momento hemos creado nuestro diseño, nuestra clase entidad, la interfaz y nuestro estructura de código interno, ¿Que nos falta?, pues únicamente probar nuestro proyecto de ejemplo:
Presione F5 para realizar las pruebas.
Presione el botón “Agregar”
Si realizo las cosas de acuerdo a las instrucciones, podrá ver el DataGridView del Form2 poblado con datos:
frm3
Haga doble Click sobre cualquier Row del datagridView para enviar los datos al Form1: 
frm4
 Ahora haga doble Click sobre un Producto ya enviado previamente:
frm5
 Bueno hemos llegado al final del articulo, si siguió el articulo completo no tendrá problemas para la implementación y adaptación de este ejemplo en sus proyecto de desarrollo.
Saludos desde Monterrey, Nuevo León México!

Ejemplo C#
Ejemplo Vb.Net
Nota: El proyecto fue desarrollado en Vs2010 Ultímate usando Framework 4.0 Client Profile