none
Ayuda con aplicacion (Excel/Blend/WPF) RRS feed

  • Pregunta

  • Muy buenas. En primer lugar acabo de inicarme en este mundo con muchas ganas de aprender. Estoy intentando realizar una aplicacion para un campeonato de coches en miniatura y se me ha ocurrido crear un interface que solo visualiza las parrillas de salida de pilotos, los tiempos y vueltas realizadas al termino de una carrera.. todo ello lo visualizaremos en una pantalla de 32" instalada en el circuito del club (los usamos para un gestor de vueltas)

    La cuestion es que tenemos una archivo Excel (SIN MACROS) que nos gestiona las eliminatorias de las carreras, donde metemos los datos como tiempos, vueltas manualmente y dicho plantilla excel nos distribuye automaticamente las posiciones de salidas para la proxima carrera... lo que querria es vincular el valor de una celda especifica, en concreto las celdas de nombre de pilotos, tiempos y vueltas de excel con un textbox, etiqueta o cualquier funcion desde Blend 3 (donde he hecho el aspecto de la interface)

    Dicho esto, me gustaria que me guien cuales son las herramientas necesarias para vincular los datos desde excel hasta blend 3 o visual Studio WPF... les pido ayuda porque por mas que busco no saco nada en claro en qué tecnologia de base de datos es la adecuada para trabajar con excel y WPF o en su caso Blend 3.. no estaria de más asegurarme antes de dar coletazos inutilmente. Gracias


    martes, 23 de febrero de 2010 23:19

Respuestas

  • Hola boloko.

    interesante lo que quieres hacer.

    Te explico:

    Para hacer esto hoy por hoy tienes basicamente 3 formas, usar una cadena de conexion contra Excel, haciendo uso de Interop o haciendo uso del nuevo formato libre OpenXml para manejar documentos Office en versiones a partir del 2007 (se pueden abrir con versiones anteriores con un complemento).

    La 1 y 2 existe bastante informacion en internet y debes de tener Office instalado en el equiipo (bueno para la primera creo que no es necesario si puedes obtener el conector por otros medios).
    Para la 3 no es necesario tener instalado Office y como es la tecnologia mas reciente, es la que te voy a explicar.

    En cualquier caso y como el sistema OpenXml es el que va a usar microsoft a partir de ahora, ya que ha creado esta especificacion para la suite office que sera usada a partir de la version 2007, te voy a poner un ejemplo de uso con esta nueva tecnologia.

    Si no coneces OpenXml puedes obtener informacion en: http://es.wikipedia.org/wiki/Office_Open_XML

    Antes que nada, hace falta que te descargues la libreria para hacer uso de OpenXML, se puede hacer mediante la API package de .net, ya que realmente son paquetes zip todos los nuevos documentos de office, pero con esta libreria te ayuda a no tener que conocer la especificacion OpenXML para la busqueda de elementos.


    Y tienes recursos en: http://openxmldeveloper.org/

    Una vez descargada la libreria, la debes referenciar en el proyecto y podras añadir los siguientes using:

    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Spreadsheet;
    using DocumentFormat.OpenXml;
    ahora tan solo deberas de añadir esta funcion en tu codigo para obtener el texto contenido en una celda:

    /// <summary>
    /// Funcion para obtener el texto de una celda en una hoja excel
    /// </summary>
    /// <param name="fileName">Nombre del archivo excel (.xlsx)</param>
    /// <param name="sheetName">Nombre de la hoja a usar</param>
    /// <param name="colName">nombre de la columna (A, B, etc.)</param>
    /// <param name="row">numero de fila</param>
    /// <returns>Texto de la celda en caso de existir, null en caso contrario</returns>
    public string GetCellValue(string fileName, string sheetName, string colName, int row)
    {
        string value = null;
    
        // abrir el archivo excel
        using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, false))
        {
            // obtener la referencia a la parte del libro de trabajo del excel
            WorkbookPart wbPart = document.WorkbookPart;
    
            // buscar la hoja con el nombre suministrado.
            Sheet theSheet = wbPart.Workbook.Descendants<Sheet>().
                Where(s => s.Name == sheetName).FirstOrDefault();
    
            // Si la hoja no existe se muestra mensaje
            if (theSheet == null)
            {
                MessageBox.Show("La hoja " + sheetName + " no existe");                    
            }
    
            // Obtener la referncia  a la parte de la hoja de trabajo
            WorksheetPart wsPart = (WorksheetPart)(wbPart.GetPartById(theSheet.Id));
            // Obtener la celda dada por el nombre de columna y fila
            Cell theCell = wsPart.Worksheet.Descendants<Cell>().
              Where(c => c.CellReference == colName + row.ToString()).FirstOrDefault();
    
            // Comprobar que existe la celda
            if (theCell != null)
            {
                // obtener el valor del elemento openXML
                value = theCell.InnerText;
    
                // Comprobar el tipo de datos de la celda para obtener el valor real.
                if (theCell.DataType != null)
                {
                    // Evaluar el tipo de datos
                    switch (theCell.DataType.Value)
                    {
                        // En el caso de contener "SharedString", se obtiene su valor de la tabla
                        // de "SharedString"
                        case CellValues.SharedString:
                            
                            // obtener el valor de la tabla "SharedString"
                            var stringTable = wbPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
    
                            // Comprobar que la tabla 'SharedString' existe para obtener el texto
                            if (stringTable != null)
                            {
                                value = stringTable.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
                            }
    
                            break;
    
                        // En caso de existir un valor booleano en la celda, se obtiene su valor
                        case CellValues.Boolean:
    
                            switch (value)
                            {
                                case "0":
                                    value = "FALSE";
                                    break;
                                default:
                                    value = "TRUE";
                                    break;
                            }
    
                            break;
    
                        // TODO: codigo para otros tipos de valores que pueda contener la celda
                    }
                }
            }
        }
    
        // retornar el valor de la celda
        return value;
    }


    Como veras, solo hace falta indicar el nombre del archivo excel (versiones a partir del 2007), la hoja donde quieres buscar y la fila y nombre de la columna y te devuelve el contenido de la celda.

    Para otros tipos de contenidos, se pueden ir añadiendo segun se necesiten.

    En un principio con esto deberias de poder comenzar, si no funciona algo comentalo.



    Saludos
    David González
    miércoles, 24 de febrero de 2010 10:38
  • Mira, no sabia que era indispensable servipack 3, lo he probado en el 2 y no funciona.

    bueno, en cualquier caso, como tenia por ahi algun codigo de antaño, te he creado la funcion anterior pero haciendo uso de interop, para esto si que es necesario que tengas el excel instalado en el equipo de desarrollo , ya que necesitaras referenciar las librerias.

    NOTA: este ejemplo tiene problemas en entornos web, ya que los privilegios necesario por defecto en la interoperabilidad COM son elevados, y en entornos web se suele usar el usuario de internet. Asi que para aplicaciones WEB es preferible de todas todas hacer uso de OpenXML.

    Pasos:

    Creas un proyecto WPF y agregas la referencia "Microsoft.Office.Interop.Excel" que debe estar en la pestaña .NET, pueden haber varias versiones (depende de tu instalacion de office).

    añades el siguiente using:

    using Microsoft.Office.Interop.Excel;


    y la Funcion :

    /// <summary>
    /// Funcion para obtener el texto de una celda en una hoja excel
    /// </summary>
    /// <param name="fileName">Nombre del archivo excel (.xlsx)</param>
    /// <param name="sheetName">Nombre de la hoja a usar</param>
    /// <param name="colName">nombre de la columna (A, B, etc.)</param>
    /// <param name="row">numero de fila</param>
    /// <returns>Texto de la celda en caso de existir, null en caso contrario</returns>
    public string GetCellValue(string _fileName, string _sheetName, string _colName, int _row)
    {            
        // Crear la referencia a la aplicacion Excel
        Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
    
        // si NO se ha podido crear la aplicacion se sale
        if (xlApp == null)
        {
            //TODO: mensaje de error
            return null;
        }
        // no mostrar la aplicacion
        xlApp.Visible = false;
        
        // obtener referncias al libro y hoja de trabajo
        Workbook wb = xlApp.Workbooks.Open(_fileName,
            Type.Missing, Type.Missing, Type.Missing, Type.Missing,
            Type.Missing, Type.Missing, Type.Missing, Type.Missing,
            Type.Missing, Type.Missing, Type.Missing, Type.Missing,
            Type.Missing, Type.Missing);
    
        // recorrer todas las hojas para buscar la deseada
        Worksheet ws = null;            
        foreach (Worksheet workSheet in wb.Worksheets)
        {
            if (workSheet.Name == _sheetName)
            {
                // guardar la hoja de trabajo encontrada y salir del bucle
                ws = workSheet;
                break;
            }
        }
    
        // Si NO se ha podido obtener la hoja de trabajo se sale
        if (ws == null)
        {
            //TODO: mensaje de error
            return null;
        }
        
        // Seleccionar un rango de celdas (en este caso solo una celda)
        Range aRange = ws.get_Range(_colName + _row.ToString(), _colName + _row.ToString());
    
        // Si NO se ha podido crear el rango
        if (aRange == null)
        {
            //TODO: mensaje de error
            return null;
        }
    
        // guardar el texto de la celda
        string ret = aRange.Text.ToString();
    
        // cerrar el documento y liberar el recurso COM
        wb.Close(false, _fileName, null);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
    
        // retornar el texto
        return ret;
    }



    Bueno, en un principio esta funcion se puede mejorar bastante, solo he realizado una version rapida para que se pareciera a la anterior, pero dejo en tus manos que trastees con ella para ver las posibilidades.


    Puede parecer mas facil trabajar con Interop, pero a la larga y con los snippets es al contrario y en cualquier caso terminara por usarse el formato OpenXml al ser mas abstracto y poder hacer cualquier cosa con los documentos Office.

    En cualquier caso, aqui tienes las 2 opciones mas usadas para que uses la que mas te guste.

    Si no te funciona algo del codigo cometalo.





    Saludos
    David González
    jueves, 25 de febrero de 2010 9:02

Todas las respuestas

  • Ah por cierto, aqui os dejo el proyecto grafico hecho con Sketchflow del blend... (ejecutar aplicacion WpfPrototype1 dentro de la carpeta y necesario tener instalado silverlight3 o framework 3.5 sp1 o tener Windosws Vista o superior)

    http://www.mediafire.com/file/vyiwyzczywi/PruebaInterfaz.rar

    Como podeis ver, en las barras de posicion de pilotos (inspiradas en la tematica de la Formula 1) ahi van los textbox o cualquier control que me permita cargar una archivo de imagenes de las dorsales de pilotos, seguido de la vinculacion de las celdas expecificas en el libro excel.
    Unas imagenes:

    Excel
    http://img52.imageshack.us/img52/2002/resizeofclip.jpg

    Boceto interfaz hecho con photoshop
    http://img534.imageshack.us/img534/4456/resizeofclasificacion2.jpg

    Esta claro que el tema de imagenes de las dorsales de pilotos, merece un tema aparte el cómo cargarlas pero de momento me basta con que me indiqueis cuales son las herramientas adecuadas y lo que necesitaria considerar para realizar esta aplicacion que solo trata de mostrar el contenido de unas determinadas celdas del libro excel.

    Saludos
    martes, 23 de febrero de 2010 23:35
  • Hola boloko.

    interesante lo que quieres hacer.

    Te explico:

    Para hacer esto hoy por hoy tienes basicamente 3 formas, usar una cadena de conexion contra Excel, haciendo uso de Interop o haciendo uso del nuevo formato libre OpenXml para manejar documentos Office en versiones a partir del 2007 (se pueden abrir con versiones anteriores con un complemento).

    La 1 y 2 existe bastante informacion en internet y debes de tener Office instalado en el equiipo (bueno para la primera creo que no es necesario si puedes obtener el conector por otros medios).
    Para la 3 no es necesario tener instalado Office y como es la tecnologia mas reciente, es la que te voy a explicar.

    En cualquier caso y como el sistema OpenXml es el que va a usar microsoft a partir de ahora, ya que ha creado esta especificacion para la suite office que sera usada a partir de la version 2007, te voy a poner un ejemplo de uso con esta nueva tecnologia.

    Si no coneces OpenXml puedes obtener informacion en: http://es.wikipedia.org/wiki/Office_Open_XML

    Antes que nada, hace falta que te descargues la libreria para hacer uso de OpenXML, se puede hacer mediante la API package de .net, ya que realmente son paquetes zip todos los nuevos documentos de office, pero con esta libreria te ayuda a no tener que conocer la especificacion OpenXML para la busqueda de elementos.


    Y tienes recursos en: http://openxmldeveloper.org/

    Una vez descargada la libreria, la debes referenciar en el proyecto y podras añadir los siguientes using:

    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Spreadsheet;
    using DocumentFormat.OpenXml;
    ahora tan solo deberas de añadir esta funcion en tu codigo para obtener el texto contenido en una celda:

    /// <summary>
    /// Funcion para obtener el texto de una celda en una hoja excel
    /// </summary>
    /// <param name="fileName">Nombre del archivo excel (.xlsx)</param>
    /// <param name="sheetName">Nombre de la hoja a usar</param>
    /// <param name="colName">nombre de la columna (A, B, etc.)</param>
    /// <param name="row">numero de fila</param>
    /// <returns>Texto de la celda en caso de existir, null en caso contrario</returns>
    public string GetCellValue(string fileName, string sheetName, string colName, int row)
    {
        string value = null;
    
        // abrir el archivo excel
        using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, false))
        {
            // obtener la referencia a la parte del libro de trabajo del excel
            WorkbookPart wbPart = document.WorkbookPart;
    
            // buscar la hoja con el nombre suministrado.
            Sheet theSheet = wbPart.Workbook.Descendants<Sheet>().
                Where(s => s.Name == sheetName).FirstOrDefault();
    
            // Si la hoja no existe se muestra mensaje
            if (theSheet == null)
            {
                MessageBox.Show("La hoja " + sheetName + " no existe");                    
            }
    
            // Obtener la referncia  a la parte de la hoja de trabajo
            WorksheetPart wsPart = (WorksheetPart)(wbPart.GetPartById(theSheet.Id));
            // Obtener la celda dada por el nombre de columna y fila
            Cell theCell = wsPart.Worksheet.Descendants<Cell>().
              Where(c => c.CellReference == colName + row.ToString()).FirstOrDefault();
    
            // Comprobar que existe la celda
            if (theCell != null)
            {
                // obtener el valor del elemento openXML
                value = theCell.InnerText;
    
                // Comprobar el tipo de datos de la celda para obtener el valor real.
                if (theCell.DataType != null)
                {
                    // Evaluar el tipo de datos
                    switch (theCell.DataType.Value)
                    {
                        // En el caso de contener "SharedString", se obtiene su valor de la tabla
                        // de "SharedString"
                        case CellValues.SharedString:
                            
                            // obtener el valor de la tabla "SharedString"
                            var stringTable = wbPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
    
                            // Comprobar que la tabla 'SharedString' existe para obtener el texto
                            if (stringTable != null)
                            {
                                value = stringTable.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
                            }
    
                            break;
    
                        // En caso de existir un valor booleano en la celda, se obtiene su valor
                        case CellValues.Boolean:
    
                            switch (value)
                            {
                                case "0":
                                    value = "FALSE";
                                    break;
                                default:
                                    value = "TRUE";
                                    break;
                            }
    
                            break;
    
                        // TODO: codigo para otros tipos de valores que pueda contener la celda
                    }
                }
            }
        }
    
        // retornar el valor de la celda
        return value;
    }


    Como veras, solo hace falta indicar el nombre del archivo excel (versiones a partir del 2007), la hoja donde quieres buscar y la fila y nombre de la columna y te devuelve el contenido de la celda.

    Para otros tipos de contenidos, se pueden ir añadiendo segun se necesiten.

    En un principio con esto deberias de poder comenzar, si no funciona algo comentalo.



    Saludos
    David González
    miércoles, 24 de febrero de 2010 10:38
  • Impresionante documento David!

    Tan pronto pueda me pongo a mirarlo a fondo y te cuento... antes tengo que ver sobre el Xp windows sp2 que siempre he sido reacio a actualizar al sp3 que es un requisito que pide para que funcione openXml segun menciona en el enlace de instalacion del OpenXMLSDKTool.msi

    Un par de datos mas a considerar, no tengo muy claro si debo elegir Codigo C# o VisualBasic que estan integrados en Visual Studio 2008 y por otro lado saber de la alternativa al openXml (VSTO por ejemplo) y cabe recordar tambien que en la aplicacion final pienso usar imagenes de las dorsales de los pilotos y su nick, en vez de solo texto (el texto irá exclusivamente para vueltas y tiempos por vuelta) esa es la idea.

    Es genial el codigo David, listo y hecho para usar pero me he topado con la limitacion del sp3 y no es mi intención desmerecer la respuesta, solo me gustaria saber la posibilidad de una alternativa rápida para operar la aplicacion en un equipo local, sin conexion a internet (la cpu del club en concreto) asi mientras soluciono esta incidencia.

    Gracias de verdad! Saludos
    miércoles, 24 de febrero de 2010 15:33
  • Mira, no sabia que era indispensable servipack 3, lo he probado en el 2 y no funciona.

    bueno, en cualquier caso, como tenia por ahi algun codigo de antaño, te he creado la funcion anterior pero haciendo uso de interop, para esto si que es necesario que tengas el excel instalado en el equipo de desarrollo , ya que necesitaras referenciar las librerias.

    NOTA: este ejemplo tiene problemas en entornos web, ya que los privilegios necesario por defecto en la interoperabilidad COM son elevados, y en entornos web se suele usar el usuario de internet. Asi que para aplicaciones WEB es preferible de todas todas hacer uso de OpenXML.

    Pasos:

    Creas un proyecto WPF y agregas la referencia "Microsoft.Office.Interop.Excel" que debe estar en la pestaña .NET, pueden haber varias versiones (depende de tu instalacion de office).

    añades el siguiente using:

    using Microsoft.Office.Interop.Excel;


    y la Funcion :

    /// <summary>
    /// Funcion para obtener el texto de una celda en una hoja excel
    /// </summary>
    /// <param name="fileName">Nombre del archivo excel (.xlsx)</param>
    /// <param name="sheetName">Nombre de la hoja a usar</param>
    /// <param name="colName">nombre de la columna (A, B, etc.)</param>
    /// <param name="row">numero de fila</param>
    /// <returns>Texto de la celda en caso de existir, null en caso contrario</returns>
    public string GetCellValue(string _fileName, string _sheetName, string _colName, int _row)
    {            
        // Crear la referencia a la aplicacion Excel
        Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
    
        // si NO se ha podido crear la aplicacion se sale
        if (xlApp == null)
        {
            //TODO: mensaje de error
            return null;
        }
        // no mostrar la aplicacion
        xlApp.Visible = false;
        
        // obtener referncias al libro y hoja de trabajo
        Workbook wb = xlApp.Workbooks.Open(_fileName,
            Type.Missing, Type.Missing, Type.Missing, Type.Missing,
            Type.Missing, Type.Missing, Type.Missing, Type.Missing,
            Type.Missing, Type.Missing, Type.Missing, Type.Missing,
            Type.Missing, Type.Missing);
    
        // recorrer todas las hojas para buscar la deseada
        Worksheet ws = null;            
        foreach (Worksheet workSheet in wb.Worksheets)
        {
            if (workSheet.Name == _sheetName)
            {
                // guardar la hoja de trabajo encontrada y salir del bucle
                ws = workSheet;
                break;
            }
        }
    
        // Si NO se ha podido obtener la hoja de trabajo se sale
        if (ws == null)
        {
            //TODO: mensaje de error
            return null;
        }
        
        // Seleccionar un rango de celdas (en este caso solo una celda)
        Range aRange = ws.get_Range(_colName + _row.ToString(), _colName + _row.ToString());
    
        // Si NO se ha podido crear el rango
        if (aRange == null)
        {
            //TODO: mensaje de error
            return null;
        }
    
        // guardar el texto de la celda
        string ret = aRange.Text.ToString();
    
        // cerrar el documento y liberar el recurso COM
        wb.Close(false, _fileName, null);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
    
        // retornar el texto
        return ret;
    }



    Bueno, en un principio esta funcion se puede mejorar bastante, solo he realizado una version rapida para que se pareciera a la anterior, pero dejo en tus manos que trastees con ella para ver las posibilidades.


    Puede parecer mas facil trabajar con Interop, pero a la larga y con los snippets es al contrario y en cualquier caso terminara por usarse el formato OpenXml al ser mas abstracto y poder hacer cualquier cosa con los documentos Office.

    En cualquier caso, aqui tienes las 2 opciones mas usadas para que uses la que mas te guste.

    Si no te funciona algo del codigo cometalo.





    Saludos
    David González
    jueves, 25 de febrero de 2010 9:02
  • Buenas David.

    de momento me han salido dos errores tipo: "Se espera una clase, un delegado...o una estructura"  ... estan causados por las palabras String y Microsoft (señalados en negrita)

    public
     string
     
    
    GetCellValue(string
     _fileName, string
     _sheetName, string
     _colName, int
     _row)
    {
    // Crear la referencia a la aplicacion Excel
    Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft .Office.Interop.Excel.Application();

    Creo que he agregado correctamente las referencias del interop de excel.

    Esta claro que todavia no me he leido el libro de programacion y de conocimientos ando bastante escaso por no decir nulo... solo confio en que aun asi, sea posible con insertar un codigo determinado para que cumpla la funcion.  Estoy toda la tarde leyendo y leyendo, dadme un pco de tiempo. Saludos

    jueves, 25 de febrero de 2010 19:33
  • Hola Boloko.

    ¿El lenguaje que usas es c#?, si es asi no deberia de dar problemas la palabra string.

    En cuanto a las referencias asegurate de que has añadido la referencia correcta que indico arriba.

    Si aun asi no te funciona, dimelo y te cuelgo el proyecto.



    Saludos
    David González
    sábado, 27 de febrero de 2010 18:58
  • Si David, uso C# al crear aplicacion WPF en visualstudio e intentado escribir el codigo tanto en windows1.xalm.cs y app.xalm.cs y nada me sigue saliendo esos dos errores de arriba.
    Tambien lo he probado en Blend3, despues de convertir el prototipo de proyecto Sketchflow a proyecto final tipo windows forms.

    Sigo buscando e informandome de como debe introducirse correctamente los codigos. Sigo necesitando tiempo pero si me ofreces colgarmelo seria interesante. Dime si necesitas que te pase algo.

    No obstante, te adjunto el proyecto (principalmente creado con Blend+Sckethflow) y el excel para si deseas verlo mejor para indicarme alguna solucion mas encaminada.
    http://www.mediafire.com/file/zmmxg5gfdia/Copia_WpfPrototype11.rar

    Gracias de nuevo David.

    domingo, 28 de febrero de 2010 12:32
  • Hola boloko.

    Te paso la direccion donde he subido un proyecto basico que hace uso del interop.


    Para no liar es un proyecto de consola basico con la funcion.

    Cuando lo descargues dimelo para poder retirarlo.

    Si tienes algun problema me lo comentas.

    Saludos
    David González
    lunes, 1 de marzo de 2010 17:07
  • Ya esta, puedes retirarlo. Iré a ver.
    lunes, 1 de marzo de 2010 19:53
  • No da ningun problema David, gracias. Ya tengo un buen punto de partida y ahora a seguir aprendiendo. Dame tiempo y te cuento.

    Gracias gracias campeon!
    martes, 2 de marzo de 2010 14:57