Welcome to MSDN Blogs Sign in | Join | Help

JK's Blog

Joseph Kiran [MSFT]
Drag and Drop Business Objects into Word/Excel 2003/2007 Surface

Many a times we may need to drag drop business objects from custom pane(Addin/document level project) or Hosted application to Word surface.

Consider a Tree Control having multiple nodes and different kinds of business objects. These business objects may need different kind the automation tasks when dropped at a particular location inside word surface. These drops also may need to validate location of the drop and allow or disallow the same.

There is no direct way to have this feature.  We must apply a workaround to achieve the same. I will try to explain how we could do this for a WPF/Windows application hosting Word internally. Below are the steps :

  1. Create a WPF/Windows application to host Word application.
  2. Reference the all the PIA's in the custom app.
  3. Create a Editor class and attach selection change event to a delegate.
  4. Create a static class to hold the global drag drop state and object.
  5. image

     

  6. Implement the selection change event as shown below
  7. image

     

  8. Implementing process drop
  9. image

     

  10. Assign the GlobalDragDropElement in before drag event of the control in the WPF/Windows app to set the drop object and selection text. The selection text is would be the unique identifier and can be a GUID.
Using LINQ in Excel VSTO with efficient Data Push to Excel Sheet

Wanted to show a simple example to demonstrate, how we could use LINQ in VSTO applications and efficiently populate data into excel. There are two ways you could chose to populate the data into excel based on your requirement.

1.       Use Open Xml SDK to open the contents of the file and populate the contents.

2.       Use VSTO excel object model to push data into the sheet.

Brief steps to fetch and populate data :

1.       Fetch Data from external source.

2.       Convert return data to business entities using LINQ.

3.       Apply business logic and transform business entities into object array.

4.       Assign object array to excel sheet using excel object model.

 

Detailed steps :  

1.       Below method fetches data from a source in xml format and uses LINQ to convert it from xml to Business objects

public void FetchAcctMovements(SearchCriteria sc, OnAppendAction onAcctMovementAppendAction)

        {

            try

            {

                using (XmlReader reader = XmlReader.Create(m_context.Client.FetchPDCBalancesNAcctMovements(sc)))

                {

                    if (HasLoginFault(reader))

                    {

                        reader.Close();

                        throw new LoginException("Login failure during AcctMovements fetch..");

                    }

 

                    var singleDayResults = reader.StreamElements("singleDayDataResult");

 

                    var singleDay =

                        from pd in singleDayResults

                        select new SingleDayMovements

                        {

                            BusinessDate = DateTime.Parse((string)pd.Element("businessDate")),

                            singleDayDataList = (

                               from singleDayData in pd.XPathSelectElements("singleDayDataList/singleDayData")

                               select new singleDayData

                               {

                                   AcctMovements = (

                                   from t in singleDayData.XPathSelectElements("AcctMovementList/AcctMovement")

                                   select new AcctMovementDetail

                                   {

                                       AcctMovement = PdcHelper.FromXml<AcctMovement>(t.ToString())

                                   }

                                   ).ToList()

                                   ,

                                   Account = new account() { accountId = singleDayData.XPathElementValue("account/accountId"), bankId = singleDayData.XPathElementValue("account/bankId"), accountType = singleDayData.XPathElementValue("account/accountType") }

                                   ,

                                   AccInfo = new AccountInfo() { AccountName = singleDayData.XPathElementValue("accountInfo/accountName"), BankName = singleDayData.XPathElementValue("accountInfo/bankName"), CurrencyCode = singleDayData.XPathElementValue("accountInfo/ns2:currencyCode"), StateCode = singleDayData.XPathElementValue("accountInfo/stateCode") }

 

                               }

                           ).ToList()

                        };

 

 

                    foreach (var singleDayMovements in singleDay)

                    {

                        singleDayMovements pdd = (singleDayMovements)singleDayMovements;

                        pdd.singleDayDataList.ForEach((pd) => { onAcctMovementAppendAction(pdd.BusinessDate, pd); });

                    }

 

                }

            }

            finally

            {

                m_context.Client.Close();

            }

 

        }

 

 

 

2.       Below method AppendAcctMovements applies the business logic as per the requirement into a flat structure. This method transforms the business entities into an object array.

Below is the sample code :

public void AppendAcctMovements(DateTime businessDay, SingleDayData singleDayData)

        {

            int totalRowCount = singleDayData.AcctMovements.Count + 1;

            int currentRowCount = 0;

            //create the object to store the dataTable data

            object[,] rowData;

            rowData = new object[totalRowCount, MAX_COL_COUNT];

 

            singleDayData.AcctMovements.ForEach(delegate(AcctMovementDetail td)

            {

                try

                {

                    int rowNum = 0;

                    //"As-Of Date     "         extract only date  businessDate

                    rowData.SetValue(businessDay.ToShortDateString(), currentRowCount, rowNum++);

                    //"As-Of-Time     "         extract only time  businessDate

                    rowData.SetValue(td.AcctMovement.asOfTime.ToShortTimeString(), currentRowCount, rowNum++);

                    //"Bank ID        "                  bankId

                    rowData.SetValue(singleDayData.Account.bankId, currentRowCount, rowNum++);

                    //"Bank Name      "                  bankName

                    rowData.SetValue(singleDayData.AccInfo.BankName, currentRowCount, rowNum++);

                    //"State "                  stateCode

                    rowData.SetValue(singleDayData.AccInfo.StateCode, currentRowCount, rowNum++);

                    //"Acct No        "                  accountId

                    rowData.SetValue(singleDayData.Account.accountId, currentRowCount, rowNum++);

                    //"Acct Type      "                  accountType

                    rowData.SetValue(singleDayData.Account.accountType, currentRowCount, rowNum++);

                    //"Acct Name      "                  accountName

                    rowData.SetValue(singleDayData.AccInfo.AccountName, currentRowCount, rowNum++);

                    //"Currency       "                  currencyCode

                    rowData.SetValue(singleDayData.AccInfo.CurrencyCode, currentRowCount, rowNum++);

                    //"AIB Type Code  "                  AcctMovementAIBCode

                    rowData.SetValue(td.AcctMovement.AcctMovementBAICode, currentRowCount, rowNum++);

                    //"Tran Desc      "                  AcctMovement\AcctMovementDescription

                    rowData.SetValue(td.AcctMovement.AcctMovementDescription, currentRowCount, rowNum++);

 

                    if (td.AcctMovement.creditDebitType.Equals("DEBIT"))

                    {

                        rowData.SetValue(td.AcctMovement.AcctMovementAmount, currentRowCount, rowNum++);

                        rowData.SetValue(0, currentRowCount, rowNum++);

                    }

                    else if (td.AcctMovement.creditDebitType.Equals("CREDIT"))

                    {

                        //Skip the debit col

                        rowData.SetValue(0, currentRowCount, rowNum++);

                        rowData.SetValue(td.AcctMovement.AcctMovementAmount, currentRowCount, rowNum++);

                    }

                    else

                    {

                        rowData.SetValue(0, currentRowCount, rowNum++);

                        rowData.SetValue(0, currentRowCount, rowNum++);

                    }

 

                    //"0 Day Flt Amt  "                  zeroDatFloatAmount

                    rowData.SetValue(td.AcctMovement.zeroDayFloatAmount, currentRowCount, rowNum++);

                    //"1 Day Flt Amt  "                  oneDayFloatAmount

                    rowData.SetValue(td.AcctMovement.oneDayFloatAmount, currentRowCount, rowNum++);

                    //"2+ Day Flt Amt "                  twoPlusDayFloatAmount

                    rowData.SetValue(td.AcctMovement.twoPlusDayFloatAmount, currentRowCount, rowNum++);

                    //"Customer Ref No "                  customerReferenceNumber

                    rowData.SetValue(td.AcctMovement.customerReferenceNumber, currentRowCount, rowNum++);

                    //"Value Date     "                  effectiveDate

                    rowData.SetValue(td.AcctMovement.effectiveDate, currentRowCount, rowNum++);

                    //"Location       "                  subAccountLocationNumber

                    rowData.SetValue(0, currentRowCount, rowNum++);

                    //"Bank Reference "                  bankReferenceNumber

                    rowData.SetValue(td.AcctMovement.bankReferenceNumber, currentRowCount, rowNum++);

                    //"Tran Status    "                  AcctMovementStatusCode

                    rowData.SetValue(td.AcctMovement.AcctMovementStatusCode, currentRowCount, rowNum++);

                    //"Movement Description Text          "         "This node occurs multiple times, first one will go to Text, second to Text2, third one goes to Text3 and so on

                    //"      AcctMovement\AcctMovementDescription\AcctMovementDescription

                    //"Movement Description Text2         "         same as above      AcctMovement\AcctMovementDescription\AcctMovementDescription

                    //"Movement Description Text3         "         same as above      AcctMovement\AcctMovementDescription\AcctMovementDescription

                    //"Movement Description Text4         "         same as above      AcctMovement\AcctMovementDescription\AcctMovementDescription

                    //"Movement Description Text5         "         same as above      AcctMovement\AcctMovementDescription\AcctMovementDescription

                    //"Movement Description Text6         "         same as above      AcctMovement\AcctMovementDescription\AcctMovementDescription

                    //"Movement Description Text7         "         same as above      AcctMovement\AcctMovementDescription\AcctMovementDescription

 

                    foreach (string desc in td.AcctMovement.AcctMovementDescriptionList.AcctMovementDescriptionCollection)

                    {

                        rowData.SetValue(desc, currentRowCount, rowNum++);

                    }

 

                    for (; rowNum < MAX_COL_COUNT; rowNum++)

                    {

                        rowData.SetValue("", currentRowCount, rowNum);

                    }

 

                }

                catch (Exception) { }

                finally

                {

                    currentRowCount++;

                }

 

 

            });

 

          // Assign to excel sheet.

            AppendAcctMovementsToExcel(rowData);

        }

 

3.      AppendAcctMovementsToExcel is the method which takes the object array and assigns it to the excelsheet. I find this method to much efficient than using a for loop to assign the values to each cell. m_dataSheet is a excel sheet member variable.

 

protected override void AppendAcctMovementsToExcel(object[,] rowData)

        {

Excel.Range dataCells = m_dataSheet.get_Range(m_dataSheet.Cells[m_currentTotalRowCount, 1],

            m_dataSheet.Cells[m_currentTotalRowCount + rowData.GetLength(0), MAX_COL_COUNT]);

            //assign data to worksheet

            dataCells.Value2 = rowData;

            m_currentTotalRowCount = rowData.GetLength(0) + m_currentTotalRowCount - 1;

        }

 

Please contact me if you need more clarity on the above.

ClickOnce Deployment using IIS / Apache Server for VSTO :

We can use Clickonce deployment almost on any Http Web Server. Clickonce deployment makes it very easy for the endusers to install the required application. I found ClickOnce deployment particularly useful when you want to distribute addins and document level customized projects for Excel / Word to the enduser in an internet/intranet scenario.

Below are the steps to configure Apache Server for ClickOnce Deployment of an Addin / Document customization projects :

1.     Open the project you would like to publish.

2.     Open the project properties. Update the properties as shown below.

a.     Publishing Folder is the location which would be embedded into the VSTO manifest to locate server for updates.

b.    Installation location is the location where the setup files are dropped.

 

 

3.     Click on the Prerequisites button and select the applications which need to be preinstalled.

 

4.     Add MIME Types to Apache server to enable ClickOnce Deployment. Apache server 2.2 version contains httpd.config at [Install Location] -> Apache Software Foundation->Apache2.2->conf

AddType application/x-ms-application application
AddType application/x-ms-manifest manifest
AddType application/octet-stream deploy
AddType application/vnd.ms-xpsdocument xps
AddType application/xaml+xml xaml
AddType application/x-ms-xbap xbap
AddType application/x-silverlight-app xap
AddType application/microsoftpatch msp
AddType application/microsoftupdate msu

5.     Click on the updates button setup the frequency to check the updates.

 

6.     Place the hyperlink pointing to the setup file for the addin in your website.

7.     When the user clicks on the link. The end user will be prompted all prerequisite installations and will then install the addin.

8.     End user can then open excel application.

9.     First time use will prompt the user to trust the addin, if the addin does not have trusted certificate.

10.  The Install prompt to the enduser may or may not come based on the security setting of the user machine. You could also configure the inclusion list security.

Note : Please check the below link for specific details.

 

How to: Configure Inclusion List Security (2007 System)

http://msdn.microsoft.com/en-us/library/bb772070.aspx

Deploy Document-Level Office 2007 Solutions with Windows Installer? (Mary Lee)

http://blogs.msdn.com/vsto/archive/2008/10/02/how-do-i-deploy-document-level-office-2007-solutions-with-windows-installer-mary-lee.aspx

How to: Add or Remove Inclusion List Entries (2007 System)

http://msdn.microsoft.com/en-us/library/bb398239.aspx

Server and Client Configuration Issues in ClickOnce Deployments 

http://msdn.microsoft.com/en-us/library/ms228998(VS.80).aspx

Troubleshooting ClickOnce Deployments

http://msdn.microsoft.com/en-us/library/fb94w1t5(VS.80).aspx

How Do I Videos - Office

http://msdn.microsoft.com/en-us/office/bb496949.aspx

Deploying Departmental Solutions via Email (Christin Boyd)

http://blogs.msdn.com/vsto/archive/2008/02/20/deploying-departmental-solutions-via-email.aspx
Software + Services using VSTO, Excel and ClickOnce Deployment with dynamic template addition/updation

Over the past couple of few week's I was working on a proof of concept to demostrate the power of Software + Services using Excel 2007, VSTO, Services and ClickOnce Deployment. I will try to demonstrate a sample step by step. It was really exciting to work on the POC. VSTO provided the ease to integrate the office applications with business data and gave enormous flexibility to develop complex business applications, deploy and update them.

                              The POC demonstrates the ease of deployment, Scalability and Richness.

VSTO + Services (High Level)

 

Deployment Server :

Apache Server / any other Web Server. Using Click Once deployment.

Refer : http://blogs.msdn.com/josephkiran/archive/2009/01/06/clickonce-deployment-using-iis-apache-server-for-vsto.aspx

MIME Types to be added for Apache Server 2.2 httpd file.

AddType application/x-ms-application application
AddType application/x-ms-manifest manifest
AddType application/octet-stream deploy
AddType application/vnd.ms-xpsdocument xps
AddType application/xaml+xml xaml
AddType application/x-ms-xbap xbap
AddType application/x-silverlight-app xap
AddType application/microsoftpatch msp
AddType application/microsoftupdate msu

Services :

WebLogic Server with XML output.

User Interface :

Excel  2007. (With Complex charts and pivots)

 

High Level Usage of Sample App :

1. User navigates to the Web Site and clicks on the hyperlink to install the add-in.

2. The add-in install checks for the pre-requisites (Office 2007 PIA,VSTO Runtime,.NET 3.5) and installs all the prerequisites, then installs the addin.

3. User can then open the excel application directly where he will find a new tab. Addin acts as a Interface for the user to download the business specific metadata.

4. User clicks on download metadata. Addin then contacts the Services to download the metadata.

5. The Metadata contains information on the latest additions of the excel templates and its location of the server. Addin then lists data as needed.

6. User can then select any of the templates and open the same.

7. The addin then downloads excel template from the deployment location specified in the metadata and writes the file to the user's Documents folder. Addin then open the excel template which contains a remote location to download the document customization.

8. Excel automatically downloads the customizations and opens the document with all the customizations in place.

9. Excel template is now ready to contact any services to download business data and show complex pivots and charts as per the business requirements.

 

Code snippets, screen shots, detailed steps coming soon...

1. MVC for VSTO Projects.

2. Using LINQ with VSTO projects.


 

Usefull Links : 

Video : Deploying Excel Document-level Customizations with Windows Installer

 

http://msdn.microsoft.com/en-us/vcsharp/cc998641.aspx

Video : Introduction to Action Panes

http://blogs.msdn.com/kathleen/archive/2007/01/04/vsto-for-mere-mortals-video-series.aspx 

Debugging in Application-Level Projects

http://msdn.microsoft.com/en-us/library/ms269003.aspx

How Do I... in Excel
 
 
Goole Docs and MS Excel Integration
 
 
Using Http Web Clients 
 

 

 

Page view tracker