Excel 2007 y Silverlight 3

marzo 16, 2010
By

Existen varias aplicaciones empresariales (algunos ERPs) que utilizan Microsoft Excel como medio de entrada de información. Siendo más especifico, por ejemplo, la declaración de nuevos elementos a un almacén en un control de inventarios puede “escribirse” utilizando un modelo de Excel (hoja de cálculo con un formato en específico). El proceso sería el siguiente:

  1. El usuario rellena una hoja de Excel con un formato determinado.
  2. El usuario abre la aplicación empresarial y desde la misma, siguiendo la interfaz particular de dicha aplicación, abre el fichero Excel.
  3. La aplicación empresarial conoce el formato de Excel y permite previsualizar (sin necesidad de tener Microsoft Office instalado) los datos antes de realizar la importación.
  4. Cuando el usuario verifica los datos previsualizados, entonces ejecuta una acción (Botón) y se importan los datos al sistema.

Utilizar Excel para estos fines es muy conveniente producto de la potencia y la facilidad que brinda este gran producto. Ahora, supongamos que esta aplicación empresarial está desarrollada con Silverlight (y de manera opcional WCF RIA Services como mecanismo de acceso a datos). ¿Cómo sería en el escenario de Silverlight el proceso anterior?

En principio habría que resaltar que en una aplicación empresarial desarrollada con Silverlight existe el código que ejecuta del lado del Servidor (la conexión con el servidor de datos y parte de la lógica del negocio) y el código Silverlight que ejecuta en el navegador web del usuario. Estas dos partes se comunican a través de la Web (Protocolo HTTP) generalmente mediante Servicios Web (SOAP o RESTFul en dependencia de la arquitectura seleccionada, dígase SOA o ROA respectivamente).

Bajo estas condiciones, una variante podría ser enviar el fichero Excel hacia el servidor, procesarlo, y una vez procesados los datos, devolverlos hacia la aplicación Silverlight para que el usuario verifique la misma. Pero note que en este esquema la información viaja doble a través de la red siendo esto un inconveniente.

A partir de la versión 2007 de Microsoft Office, el formato de los documentos pasó a ser de un binario críptico (versiones 2003 y anteriores) a un formato estándar bien documentado que puede describirse de manera simplista como un ZIP que contiene un gran fichero XML (Más información Microsoft Open XML SDK). Entonces, si una hoja de cálculo de Excel 2007 es un ZIP que contiene un XML, es posible directamente desde Silverlight acceder a un fichero Excel 2007.

Desde .NET se puede utilizar la API System.IO.Packaging para acceder a los ficheros de Office 2007 de manera simple, pero estamos trabajando con Silverlight que como sabemos contiene un subconjunto minimal de las API que brinda .NET, siendo System.IO.Packaging una de las no disponibles. Pero esto no representa un gran problema debido a que existen diversas bibliotecas para el manejo de ficheros ZIP desde Silverlight, y una vez accedido el ZIP, puede utilizarse LINQ to XML para navegar por el mismo.

En el post http://www.silverlightshow.net/items/An-Excel-file-Viewer-in-Silverlight-4.aspx se realiza una descripción detallada del proceso de acceso al fichero con formato Excel 2007 y se detallando el formato del mismo. Además se muestra una aplicación creada con Silverlight 4 que demuestra el proceso. En nuestro post, utilizaremos la biblioteca XSLXparsingLib creada en el post referenciado para lograr los objetivos propuestos al inicio.

excel-silverlight

Figura 1. A la izquierda una hoja de Excel y a la derecha su visualización mediante el DataGrid de Silverlight 3

Como puede apreciarse en la figura 1, se ha creado una aplicación Silverlight 3 de prueba (parte derecha) que accede directamente a una hoja de Excel (parte izquierda) y visualiza los datos en un DataGrid.

El código del botón “Abrir Excel” sería el que aparece a continuación:

private void cmdOpen_Click(object sender, RoutedEventArgs e)
{
    OpenFileDialog ofd = new OpenFileDialog();
    ofd.Multiselect = false;
    ofd.Filter = "Excel 2007 (*.xlsx)|*.xlsx";
    var dialogResult = ofd.ShowDialog();
    if (dialogResult.HasValue && dialogResult.Value)
    {
        try
        {
            var excelFile = new XLSXReader(ofd.File);
            var sheets = excelFile.GetListSubItems();
            var content = excelFile.GetData(sheets[0]);
            var headers = content.First();

            dataGrid1.Columns.Clear();
            foreach (DictionaryEntry pair in headers)
            {
                dataGrid1.Columns.Add(new DataGridTextColumn
                  {
                      Header = pair.Value,
                      Binding = new Binding(pair.Key.ToString())
                  });
            }

            dataSource = content.Skip(1).ToDataSource();
            dataGrid1.ItemsSource = dataSource;
        }
        catch (Exception err)
        {
            MessageBox.Show("No se puede abrir el archivo. Puede que el archivo se esté utilizando o no contenga el formato correcto. " + err.Message, "Ha ocurrido un error", MessageBoxButton.OK);
        }
    }
}

De esta forma el fichero Excel 2007 se procesa directamente en el navegador web del cliente mostrándose los datos en el DataGrid. La información se obtiene como IEnumerable<IDictionary> y mediante el método extensor ToDataSource() y utilizando reflection se convierten los diccionarios en tipos propios (por cada columna del Excel se crea una propiedad en el tipo automáticamente generado) permitiendo así el Binding con el DataGrid (Ver http://blog.bodurov.com/How-to-Bind-Silverlight-DataGrid-From-IEnumerable-of-IDictionary). Una vez que el usuario valida la información pues se envía una única vez hacia el servidor (vía servicio web o mediante los mecanismos del WCF Ria Services) optimizando así el ancho de banda y el costo del procesamiento del lado del servidor.

DESCARGAR CÓDIGO FUENTE: Weboomania.ExcelSilverlightTest.zip

Tags: ,

20 Responses to Excel 2007 y Silverlight 3

  1. javier on mayo 7, 2010 at 6:21 pm

    hola. puedes poner el proyecto en donde muestras tu ejemplo.
    Saludos.!

    • Alejandro Tamayo
      Alejandro Tamayo Castillo on mayo 8, 2010 at 5:34 pm

      Hola Javier,

      Puse el código fuente. Como verás es bastante simple.

      Saludos

  2. Ninoska on noviembre 24, 2010 at 7:35 am

    Hola gracias por tu interes, es posible que este archivo de excel(que es realmente un XML) se pueda guardar en un campo de una tabla de una base de datos en sql??? gracias

    youtube downloader, music, youtube downloader

    • Alejandro Tamayo
      Alejandro Tamayo on noviembre 24, 2010 at 4:16 pm

      El .xlsx es un ZIP que tiene varios XML pero puede tener también otros elementos como imágenes por ejemplo. Si quieres almacenar el fichero en una base de datos lo puedes hacer utilizando un campo de tipo binario. En MySQL por ejemplo es BINARY. Si utilizas SQL Server 2008 puedes explotar la característica de FileStream para un mejor almacenamiento del fichero binario.

  3. Fernando on marzo 22, 2011 at 7:51 pm

    Holas excelente libreria bueno ahora la estoy usando pero tengo un problema cuando en la hoja excel tengo una fecha con este formato 13/09/2011 no me reconoce como cadena.!!! creo que hace las operaciones . gracias..:D

  4. Jhonman on marzo 28, 2011 at 1:58 pm

    Hola creo que el problema esta en el archivo de excel, dale a la columna formato de texto, ya que por default el formato es “general”.

  5. Miguel Angel Reyes Xinaxtle on abril 16, 2011 at 1:59 pm

    Esta exelente pero no he podido usar los datos en que recibe del excel podrias indicarme por favor de una panera en la cual puede mostarlo

    te lo agradeceria mucho

    saludos

    • alejandro on abril 22, 2011 at 8:17 pm

      tenia el mismo problema y lo solucione asi:
      var list = this.dataGrid1.ItemsSource.Cast().ToList();
      var obj = list[1]; //accede a la primera fila del grid
      var id = (string)obj.GetType().GetProperty(“A”).GetValue(obj, null); //accede al valor de la columna a de la primera fila.

      espero te sirva

  6. Miguel Angel Reyes Xinaxtle on abril 16, 2011 at 2:26 pm

    he intentado usar current pero no me ha servido ya que no puedo acceder a sus valores con ninguna propiedad ayudame por favor

  7. Eduardo on abril 27, 2011 at 10:26 am

    Al pasar una fecha al grid desde excel no me da el dato si no un numero ejemplo “04/04/2011″ en el grid pone 40663. que es lo que ocurre.

  8. ivan castillo on julio 1, 2011 at 1:01 pm

    Hola buenas tardes, esta muy bueno tu tutorial, pero que pasa si quiero abrir archivo de excel de otra version, puesto qeu hay empresas que manejan excel 2003.

    gracias!!

    Felicidades por tu informacion, esta muy buena

    • Alejandro Tamayo
      Alejandro Tamayo on abril 17, 2012 at 9:36 am

      Bueno, eso es un problema mayor. Los xls están escritos en binario y son formatos cerrados. Hay bibliotecas por ahí para abrirlos pero no se supone que se haga. A partir de Office 2007 se están utilizando formatos abiertos. El XLSX es un .ZIP con un XML declarativo bien documentado :)

  9. Alfonso B on enero 30, 2012 at 9:21 pm

    Hola

    Si quiero pasar como parametro el datasource, cómo podría recibirlo en un Web Service para que este lo cambiara postariormente a un datatable?

    De antemano mil gracias.

    Saludos

    • Alejandro Tamayo
      Alejandro Tamayo on abril 17, 2012 at 9:46 am

      Bueno, tienes varias formas. Si el esquema es fijo (conoces las columnas) utiliza los RIA Services que están para eso. Si el esquema es variable, pues tendrás que serializar de alguna forma (a JSON o XML) y hacer un post hacia el servidor (usando AJAX o de manera tradicional). Luego deserializas obtienes los datos (probablemente como diccionarios anidados).

  10. Drognan on octubre 23, 2012 at 8:42 am

    Hola Alejandro,Felicidades por tu post.

    He encontrado una anomalia al porcesas fechas, estas se leen de manera erronea, no se si sabes el porque, muchas gracias.

    • Alejandro Tamayo
      Alejandro Tamayo on octubre 23, 2012 at 6:20 pm

      Bueno, tendrías que ser más específico. En cualquier caso, la fecha en inglés es mm-dd-yyyy (el mes antes que el día). Si el formato es numérico entonces es un entero que cuenta los segundos desde 1970.

  11. Drognan on octubre 24, 2012 at 3:32 am

    Hola Alejandro, gracias por tu pronta contestación, el ejemplo es como dice un comentario arriba,

    “Al pasar una fecha al grid desde excel no me da el dato si no un numero ejemplo “04/04/2011″ en el grid pone 40663. que es lo que ocurre.”

    el formato de la celda de excel es de fecha…

    Gracias

    • Alejandro Tamayo
      Alejandro Tamayo on octubre 24, 2012 at 2:12 pm

      Las fechas se almacenan como enteros. Utiliza el siguiente código para obtener un DateTime:

      double d = 40663;
      DateTime conv = DateTime.FromOADate(d);

  12. pepe on julio 29, 2013 at 11:10 pm

    Hola Alejandro,podrias ayudarme y como seria al reves. mi applicacion hecha en (Silverlight, Ria Services, C#, Web, VS2010,SQL express 2008) de un DataGrid caragado de un Context.datos desde SQL exportar a Excel pero dentro del navegador. mil gracias.

    • Alejandro Tamayo
      Alejandro Tamayo on julio 30, 2013 at 8:45 pm

      Para lograr esto que quieres, tienes que sortear dos obstáculos: acceder a un fichero de la PC del cliente y tener un código compatible con Silverlight para generar el Excel.

      A partir de Silverlight 3.0, puedes utilizar el OpenFileDialog (http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2009/03/18/a-quick-look-at-silverlight-3-save-file-dialog.aspx) para pedirle permiso de escritura al usuario. Al mismo le aparece un cuadro de diálogo de salva, él escoge la dirección donde quiere guardar y entonces tú como desarrollador tendrías acceso de escritura al fichero (utilizando un FileStream). De hecho, el código es muy similar al que aparece en este artículo, lo que tendrías que pedirle al OpenFileDialog que te cree un fichero, en vez de abrir uno existente.
      Una vez con la instancia del FileStream, tendrías que escribir el fichero en formato xlsx compatible con Excel. Ésta es la parte complicada, ya que puede que tengas una biblioteca .NET que te permita crear un fichero Excel, pero eso no te sirve ya que necesitas dicho código compilado para Silverlight, que es una plataforma diferente a la .NET a que estás acostumbrado. Una variante pudiera ser, obtener el código fuente de dicha biblioteca de Excel e intentar portarla a Silverlight, cosa que puede ser compleja y trabajosa ya que todos los tipos de .NET no están disponibles en Silverlight. En dependencia de la complejidad con que quieras la hoja de Excel, puedes incluso hacerla tú mismo a mano, recuerda que es un ZIP con un XML dentro. Puedes utilizar el código de este artículo y en vez de parsear el XML, pues crear un XML nuevo y compactarlo en un ZIP. En cualquier caso, no es tarea simple y es por ello que se recomienda hacerlo server-side donde tienes toda la potencia de .NET y bibliotecas ya desarrolladas para ello (Recuerda que no puedes utilizarlas en Silverlight tal y como son porque es una plataforma diferente a .NET).

      En dependencia de tus objetivos, hay una última variante, que no me gusta mucho pero puede serte útil y es con Silverlight 4. Esta versión te permite acceder al Excel de la PC del usuario, utilizando los objetos COM. Aquí tendrías toda la potencia del Excel de la PC del usuario para hacer los informes tan complejos como quieras, pero la limitante (y es por ello que no me gusta) es que el usuario tiene que tener instalado Excel/Office con la versión que estés utilizando. De todas formas aquí te dejo un ejemplo: http://www.dotnetcurry.com/ShowArticle.aspx?ID=576

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

*

Acerca del autor...

Alejandro Tamayo

Web: http://www.linkedin.com/in/atamayocastillo
Alejandro Tamayo
Professor, Researcher, Developer, Consultant and technology enthusiast. Master of Science (MSc) in Computer Science and member of Weboo Research Group.Leer completo