Como: Trabajar en Excel 2010 con datos de Duet Enterprise y SAP


Un compañero me lanzó la pregunta… supongo que de un partner, a propósito de la posibilidad de trabajar desde Microsoft Office Excel 2010, con los datos y la información obtenida en las listas de contenido externo (ECL) por medio de Duet Enterprise (alias BCS), de SAP.

¿Quizá desde Microsoft Office InfoPath 2010?

Las listas de contenido externo no disponen de la vista en Excel, lo que nos complica el que se pueda trabajar con las Office Web Applications (OWA) en Excel de forma inmediata.

Ahora que el desarrollo, puede ayudarnos un poquito.

Encontré ésta entrada de blog que explica como implementar en hojas de libro de Excel 2010, la obtención de la información, utilizando los servicios de Duet.

Y al final de la entrada, os complemento la solución, con dos (2) interesantes aproximaciones de creación de Add-ins.

Extraido y traducido de: Joyanta Sen(Microsoft Francia)

 

Este artículo contiene una descripción paso a paso de un ejemplo, basado en la integración de una lista de Duet Enterprise dentro de Excel 2010. El objetivo es mostrar la lista de clientes en una hoja de cálculo de Excel 2010.

Pasos preliminares

Para utilizar una lista externa basada en un tipo de contenido externo a Excel, en una aplicación desarrollada mediante Visual Studio Tools para Office (VSTO), debe hacer lo siguiente:

  • Crear una lista externa basada en un tipo de contenido externo

Aplicación de Excel desarrollada con VSTO

1. Utilizando Visual Studio 2010, crear un proyecto VSTO de libro de Excel.

2. Crear una clase auxiliar denominada SPHelper en una carpeta de proyecto llamada Helpers.

3. Agregar al proyecto un tipo correspondiente a la estructura Customer, en una clase denominada CommonTypes.cd en el directorio Common .

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DuetExcelWorkbook.Common
{
    public struct CustomerType
    {
        public string FirstLineName;
        public string CountryCode;
        public string AddressregionCode;
        public string AddresscityName;
    }
}

 

4. Agregar el ensamblado OM client:

C:\Programs\Common File\Microsoft Shared\Web Server Extensions\14\ISAPI\

4.1 Agregar a las referencias del proyecto los siguientes ensamblados:

Microsoft.SharePoint.Client.dll

Microsoft.SharePoint.Client.Runtime.dll

4.2 En Common crear una clase denominada SPHelpers.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using System.Linq.Expressions;
using System.Xml;
namespace DuetExcelWorkbook.Helpers
{
    public static class SPHelper
    {
        public static List<CustomerType> GetCustomerList(string TargetSiteUrl, string TargetListName)
        {
            List<CustomerType> CustomerList = new List<CustomerType>();
            try
            {
                ClientContext clientContext = new ClientContext(TargetSiteUrl);
                List externalList = clientContext.Web.Lists.GetByTitle(
                    TargetListName);
                // To properly construct the CamlQuery and
                // ClientContext.LoadQuery,
                // we need some View data of the Virtual List.
                // In particular, the View will give us the CamlQuery
                // Method and Fields.
                clientContext.Load(
                    externalList.Views,
                    viewCollection => viewCollection.Include(
                        view => view.ViewFields,
                        view => view.HtmlSchemaXml));
                // This tells us how many list items we can retrieve.
                clientContext.Load(clientContext.Site,
                    s => s.MaxItemsPerThrottledOperation);
                clientContext.ExecuteQuery();
                // Let's just pick the first View.
                View targetView = externalList.Views[0];
                string method = ReadMethodFromViewXml(
                    targetView.HtmlSchemaXml);
                ViewFieldCollection viewFields = targetView.ViewFields;
                CamlQuery vlQuery = CreateCamlQuery(
                    clientContext.Site.MaxItemsPerThrottledOperation,
                    method,
                   viewFields);
                Expression<Func<ListItem, object>>[] listItemExpressions =
                    CreateListItemLoadExpressions(viewFields);
                ListItemCollection listItemCollection =
                    externalList.GetItems(vlQuery);
                // Note: Due to limitation, you currently cannot use
                // ClientContext.Load.
                //       (you'll get InvalidQueryExpressionException)
                IEnumerable<ListItem> resultData = clientContext.LoadQuery(
                    listItemCollection.Include(listItemExpressions));
                clientContext.ExecuteQuery();
                foreach (ListItem li in resultData)
                {
                    // Now you can use the ListItem data!
                    CustomerType customer = new CustomerType();
                    customer.FirstLineName = li["FirstLineName"].ToString();
                    //customer.AddresscityName = li["AddresscityName"].ToString();
                    //customer.AddressregionCode = li["AddressregionCode"].ToString();
                    customer.CountryCode = li["CountryCode"].ToString();
                    CustomerList.Add(customer);
                    Console.WriteLine("First Name: {0} Country : {1} \n", li["FirstLineName"].ToString(), li["CountryCode"].ToString());
                    // Note: In the CamlQuery, we specified RowLimit of
                    // MaxItemsPerThrottledOperation.
                    // You may want to check whether there are other rows
                    // not yet retrieved.               
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return CustomerList;
        }
        /// <summary>
        /// Parses the viewXml and returns the Method value.
        /// </summary>       
        private static string ReadMethodFromViewXml(string viewXml)
        {
            XmlReaderSettings readerSettings = new XmlReaderSettings();
            readerSettings.ConformanceLevel = ConformanceLevel.Fragment;
            XmlReader xmlReader = XmlReader.Create(
                new StringReader(viewXml), readerSettings);
            while (xmlReader.Read())
            {
                switch (xmlReader.NodeType)
                {
                    case XmlNodeType.Element:
                        if (xmlReader.Name == "Method")
                        {
                            while (xmlReader.MoveToNextAttribute())
                            {
                                if (xmlReader.Name == "Name")
                                {
                                    return xmlReader.Value;
                                }
                            }
                        }
                        break;
                }
            }
            throw new Exception("Unable to find Method in View XML");
        }
        /// <summary>
        /// Creates a CamlQuery based on the inputs.
        /// </summary>       
        private static CamlQuery CreateCamlQuery(
            uint rowLimit, string method, ViewFieldCollection viewFields)
        {
            CamlQuery query = new CamlQuery();
            XmlWriterSettings xmlSettings = new XmlWriterSettings();
            xmlSettings.OmitXmlDeclaration = true;
            StringBuilder stringBuilder = new StringBuilder();
            XmlWriter writer = XmlWriter.Create(
                stringBuilder, xmlSettings);
            writer.WriteStartElement("View");
            // Specifies we want all items, regardless of folder level.
            writer.WriteAttributeString("Scope", "RecursiveAll");
            writer.WriteStartElement("Method");
            writer.WriteAttributeString("Name", method);
            writer.WriteEndElement();  // Method
            if (viewFields.Count > 0)
            {
                writer.WriteStartElement("ViewFields");
                foreach (string viewField in viewFields)
                {
                    if (!string.IsNullOrEmpty(viewField))
                    {
                        writer.WriteStartElement("FieldRef");
                        writer.WriteAttributeString("Name", viewField);
                        writer.WriteEndElement();  // FieldRef
                    }
                }
                writer.WriteEndElement();  // ViewFields
            }
            writer.WriteElementString(
                "RowLimit", rowLimit.ToString(CultureInfo.InvariantCulture));
            writer.WriteEndElement();  // View
            writer.Close();
            query.ViewXml = stringBuilder.ToString();
            return query;
        }
        /// <summary>
        /// Returns an array of Expression used in
        /// ClientContext.LoadQuery to retrieve
        /// the specified field data from a ListItem.       
        /// </summary>       
        private static Expression<Func<ListItem, object>>[]
            CreateListItemLoadExpressions(
            ViewFieldCollection viewFields)
        {
            List<Expression<Func<ListItem, object>>> expressions =
                new List<Expression<Func<ListItem, object>>>();
            foreach (string viewFieldEntry in viewFields)
            {
                // Note: While this may look unimportant,
                // and something we can skip, in actuality,
                //       we need this step.  The expression should
                // be built with local variable.               
                string fieldInternalName = viewFieldEntry;
                Expression<Func<ListItem, object>>
                    retrieveFieldDataExpression =
                    listItem => listItem[fieldInternalName];
                expressions.Add(retrieveFieldDataExpression);
            }
            return expressions.ToArray();
        }
    }

5. Ahora necesita agregar código de la interfaz de usuario, o lo que es lo mismo, el código que llama a la clase OM Client.

5.1 Agregar un cinta de funcionalidad al proyecto (Ribbon).

5.2 Modificar la siguientes propiedades de la cinta:

Label: Duet Enterprise
Name: tabDuet

5.3 Agregar un botón a la cinta de opciones y cambiar las propiedades
siguientes:

ControlSize: RibbonControlSizeLarge
Label:
Customers
OfficeImageId:
SlideMasterChartPlacehoderInsert

6. Añadir a la función buttonCustomers_Click() el código siguiente.

private void buttonCustomers_Click(object sender, RibbonControlEventArgs e)
        {
            List<CustomerType> result = new List<CustomerType>();
            try
            {
                result = SPHelper.GetCustomerList("http://litware", "SAPCustomers");
                //string[] Names = new string[];
                //string[] Countries;
                List<string> Names = new List<string>();
                List<string> Countries = new List<string>();
                int counter = 0;
                // Fill the collections
                foreach (var item in result)
                {
                    // Add the customers in the ListView
                    Names.Add(item.FirstLineName);
                    Countries.Add(item.CountryCode);
                         
                    counter++;
                }
                // Create a data table with two columns.
                System.Data.DataTable table = new DataTable();
                DataColumn column1 = new DataColumn("Name", typeof(string));
                DataColumn column2 = new DataColumn("Country", typeof(string));
                table.Columns.Add(column1);
                table.Columns.Add(column2);
                // Add the four rows of data to the table.
                DataRow row;
                for (int i = 0; i < counter; i++)
                {
                    row = table.NewRow();
                    row["Name"] = Names[i];
                    row["Country"] = Countries[i];
                    table.Rows.Add(row);
                }
                Microsoft.Office.Tools.Excel.ListObject list1 =
                    Globals.Sheet1.Controls.AddListObject(Globals.Sheet1.Range["A1", "B4"], "list1");
                // Bind the list object to the table.
                list1.SetDataBinding(table);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                throw;
            }
        }

7. Ejecutar Visual Studio

Nota: No olvide ejecutar Visual Studio utilizando la identidad del usuario correcto. El usuario debe tener el permiso de lectura a la lista de Customers.

Haga clic en la opción de la cinta, Duet Enterprise y a continuación, haga clic en Customers. Se agregará la lista de clientes a Microsoft Excel.

 

El articulo original se encontraba en: Duet Enterprise and Excel 2010 pero ya no está disponible 🙁

Tal como os anunciaba al comienzo de la entrada, el artículo en que se basa ésta entrada es:

Consumo de datos externos con Servicios de conectividad empresarial de SharePoint Server 2010 y complementos de Excel 2010

Además del código a descargar desde la página relacionada

Business Connectivity Services Excel 2010 Add-In

http://archive.msdn.microsoft.com/odcspbcsexceladdin

 

No dejeis de echarle un vistazo a la actualización

SharePoint 2010: Consuming External Data Using BCS and Excel Add-Ins

http://code.msdn.microsoft.com/SharePoint-2010-Consuming-2b3410d3

Esto es todo lo referente a Excel, pero las Visual Studio Tool for Office (VSTO) también nos dan soluciones para Microsoft Office PowerPoint 2010.

Using Business Connectivity Services and Visual Studio Add-ins to to Create PowerPoint Charts

 

Espero os sea de utilidad.

Comments (0)

Skip to main content