jueves, 18 de septiembre de 2014

El Demo del Día: Copiar Datos de Excel en el DataGridView de WinForms

Copiar Datos de Excel en el DataGridView de WinForms

Después de un tiempo, volvemos a publicar un nuevo Demo, esta vez a pedido de un alumno, que desea copiar que su aplicación tenga la funcionalidad de copiar datos de la Grilla (DataGridView) a Excel (esto es automático, no es necesario programar nada) y desde Excel hacia la aplicación (esto si requiere de programar usando el objeto Clipboard de WinForms).

Como siempre nuestro desarrollo lo haremos con Listas de Objetos (como debe ser para ahorrar memoria y no con DataSet), ademas usaremos Reflection para convertir los datos que vienen como cadenas desde Excel al tipo de datos adecuado del objeto.

Crear una Aplicación Windows Forms en C#

Crear un nuevo proyecto de tipo Windows Forms y llamarle "CopiarExcel". Cambiarle de nombre al formulario por el de "frmProducto".

Crear la clase: "beProducto" para la lista de objetos

using System;
namespace CopiarExcel
{
    public class beProducto
    {
        public int IdProducto { get; set; }
        public string Nombre { get; set; }
        public decimal Precio { get; set; }
        public short Stock { get; set; }
    }
}

Agregar un control DataGridView sobre el formulario, cambiarle al nombre de "dgvProducto" y acoplarlo para que se vea similar a la siguiente figura:


Escribir el siguiente código en el formulario:

using System.IO;
using System.Reflection;

namespace CopiarExcel
{
    public partial class frmProducto : Form
    {
        private List<beProducto> lbeProducto;

        public frmProducto()
        {
            InitializeComponent();
        }

        private void cargarProductos(object sender, EventArgs e)
        {
            lbeProducto = new List<beProducto>();
            Random oRandom = new Random();
            beProducto obeProducto;
            for(int i=1;i<=10;i++)
            {
                obeProducto = new beProducto();
                obeProducto.IdProducto = i;
                obeProducto.Nombre = String.Format("Producto {0}", i);
                obeProducto.Precio = oRandom.Next(100)+10;
                obeProducto.Stock = (short)(oRandom.Next(10) + 1);
                lbeProducto.Add(obeProducto);
            }
            dgvProducto.DataSource = lbeProducto;
        }

        private void pegarExcel(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.V)
            {
                string formato = DataFormats.CommaSeparatedValue;
                object contenido = Clipboard.GetData(formato);
                if (contenido != null && contenido is MemoryStream)
                {
                    byte[] buffer;
                    using (MemoryStream ms = (MemoryStream)contenido) buffer = ms.ToArray();
                    string lista = Encoding.UTF8.GetString(buffer).Replace("\r\n", ",");
                    string[] data = lista.Split(',');
                    PropertyInfo[] propiedades = lbeProducto[0].GetType().GetProperties();
                    if ((data.Length - 1) % propiedades.Length == 0)
                    {
                        beProducto obeProducto = null;
                        PropertyInfo propiedad;
                        int c = 0;
                        Type tipo = null;
                        while (c < data.Length - 1)
                        {
                            for (int i = 0; i < propiedades.Length; i++)
                            {
                                if (i == 0) obeProducto = new beProducto();
                                propiedad = obeProducto.GetType().GetProperty(propiedades[i].Name);
                                tipo = propiedad.PropertyType;
                                propiedad.SetValue(obeProducto, Convert.ChangeType(data[c], tipo));
                                if (i == propiedades.Length - 1) lbeProducto.Add(obeProducto);
                                c++;
                            }
                        }
                        dgvProducto.DataSource = null;
                        dgvProducto.DataSource = lbeProducto;
                    }
                    else MessageBox.Show
                    ("Numero de columnas a copiar del Excel y la Grilla deben ser iguales");
                }
                else MessageBox.Show("No hay un rango de celdas a copiar");
            }
        }
    }
}

Nota: Para copiar desde Excel a la grilla se debe pulsar la tecla Ctrl + V y la cantidad de columnas debe ser la misma que la de la grilla (en realidad la de las propiedades de la clase beProducto o la que fuera).

Probar la Aplicación Creada

Grabar el proyecto y ejecutarlo con F5. Se mostrará la siguiente ventana con los datos de los productos creados en el evento Load del formulario:


Crear un archivo de Excel con la misma estructura de los Productos, tal como se muestra a continuación:


Copiar (Ctrl + C) el rango de celdas que se desea llevar a la aplicación (sin incluir las cabeceras) y en cualquier celda de la grilla Pegar (Ctrl + V), y se copiaran los registros seleccionados en Excel, tal como se muestra a continuación:


Si desean se puede ir copiando por partes (filas) pero si es necesario seleccionar todas las columnas, ya que el objeto necesita de valores.

Nota: El procedimiento contrario, es decir desde la Aplicación (DataGridView) a Excel es automatico, solo hay que marcar el rango de celdas del DataGridView, Ctrl + C y luego en Excel Ctrl + V.

Comentario Final

En este post hemos visto como agregar la funcionalidad de Copiar Datos Externos a la aplicación, en este caso desde Excel, pero el procedimiento sera similar desde cualquier origen. Para ello hemos usado el objeto ClipBoard y para trabajar con objetos hemos usado Reflection, lo que quiere decir que el demo lo puedes probar con cualquier objeto que definan.

Saludos a todos los visitantes asiduos del Blog y ya saben que pueden hacer sus pedidos en los comentarios.

Descarga:




14 comentarios:

  1. Buen aporte profe gracias, exelente su for dentro del wihile, yo simplemente cogía el clipboard.GetData y lo separaba por tabs que es el separador en excel.

    ResponderBorrar
  2. Buen aporte profesor, ahora voy a integrarlo a la librería de la grilla con formato y paginación para que esté más completo.

    Saludos Cordiales.

    ResponderBorrar
  3. Genial aporte profesor, muchas gracias por compartirlo.

    ResponderBorrar
  4. Muy buena aplicación profesor, esta muy interesante...

    ResponderBorrar
  5. Este comentario ha sido eliminado por el autor.

    ResponderBorrar
  6. Mi consulta es, como se invoca pegarExcel y cargarProductos?? que evento seria?

    ResponderBorrar
  7. La función cargarProductos() esta asociado al evento Load del formulario y la función pegarExcel al evento KeyDown del DataGridView

    ResponderBorrar
  8. Otra consulta más, funciona bien pero por cada celda me copia la fila entera concatenada con ";". que puede ser?

    ResponderBorrar
  9. Kily es el separador, en tu caso no es coma sino punto y coma:
    string lista = Encoding.UTF8.GetString(buffer).Replace("\r\n", ";");
    string[] data = lista.Split(';');

    ResponderBorrar
  10. perfecto!!! ahi anduvo. Muchas gracias!

    SAludos

    ResponderBorrar
  11. Hola tengo una duda con mi proyecto el cliente en ocasiones tiene que repetir datos pero si son mas de 10 registros no quiere ingresar digitar tanto solo copiar y pegar desde otro lado ya sea excel access o desde quizas otro datagrid del mismo sistema solo abierto 2 veces, entonces estado tratando de acoplar lo que ya tengo a la forma como indica pero no tengo resultados, respecto a cuando llama namescape copiarexcel /end namescape bueno yo trabajo con vbasic asi que converti su codigo pero cuando pongo namescape mis codigos salen con error subrayados en la parte del handles boton.click y entonces nose como solucionar eso. Espero me pueda ayudar.

    ResponderBorrar