如何使用VSTO加载项项目轻松创建Excel UDF

时间:2009-06-05 19:07:15

标签: c# visual-studio-2010 vsto excel-2007

我要做的是使用VSTO的C#“Excel 2007加载项”项目类型为Excel创建用户定义函数(UDF)(因为我只想生成一些常规UDF)。因为我只是想学习基础知识(无论如何在这个阶段),这就是我的代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Excel;
using Microsoft.Office.Tools.Excel.Extensions;
using System.Runtime.InteropServices;

namespace ExcelAddIn1
{
    public partial class ThisAddIn
    {
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {}

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {}

        //My UDF
        public static double HeronicCal(int a, int b, int c)
        {
            //first compute S = (a+b+c)/2
            double S = (a + b + c) / 2;    
            double area = Math.Sqrt(S * (S - a) * (S - b) * (S - c));
            return area;
        }

        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }            
        #endregion
    }
}

它编译得很好,当我运行时,Excel弹出一个新的电子表格,当我查看“加载项”列表(在Excel选项中)时,我可以在列表中看到我的加载项(设置为“启动时加载”。但是这里出现了我的问题,当我尝试用Excel中的Excel调用我的UDF时,Excel无法找到该方法!

我想象的是错误的,我必须将我的方法标记为Excel UDF(使用方括号 - 例如在编写webservices时执行 - &gt;“[WebService]”)。但是我无法追踪这个标签(因为我不确定我的预感是否正确),这就是为什么我决定在这里找你们好的人。

所以我的问题基本上是 - 从我的代码到哪里,有什么简单的方法让我的UDF可以访问Excel?如果有,怎么样?

我真的想留在VSTO项目类型(插件,工作簿,模板)中,因为我当前项目的总体目标是确定使用VS2010 / Excel2007的C#UDF执行是否可以接受速度。为了测试这个,我正在使用Windows7RC和VS2010 beta1。

4 个答案:

答案 0 :(得分:19)

VSTO不支持创建Excel UDF。自动化加载项可以在.Net中创建,并且似乎是Microsoft批准的方式。

你应该看看ExcelDna - http://www.codeplex.com/exceldna。 ExcelDna允许托管程序集通过本机.xll接口将用户定义的函数(UDF)和宏公开给Excel。该项目是开源的,可以自由地进行商业用途。您会发现基于.Net的UDF的性能类似于Excel的原生.xll加载项。 Excel 2007的功能如大表,长Unicode字符串和多线程重新计算都受支持。

使用ExcelDna,上面发布的函数将暴露给没有VSTO的Excel - 您可以将代码放入基于xml的.dna文件或将其编译为.dll。

公开UDF的.dna文件如下所示:

<DnaLibrary Language="C#">
   using System;
   using ExcelDna.Integration;

   public class MyFunctions
   {
      [ExcelFunction(Description="Calculate Stuff", Category="Cool Functions")]
      public static double HeronicCal(int a, int b, int c)
      {
         //first compute S = (a+b+c)/2
         double S = (a + b + c) / 2;
         double area = Math.Sqrt(S * (S - a) * (S - b) * (S - c));
         return area;        
      }
   }
</DnaLibrary>

更新:目前,开始使用Excel-DNA的最简单方法是在Visual Studio中创建一个新的类库项目,然后从NuGet添加“ExcelDna.AddIn”包。这会产生一个入门加载项 - 只需粘贴代码并按F5即可运行。

答案 1 :(得分:9)

看起来Eric Carter在这里有一个胜利者:

http://blogs.msdn.com/b/eric_carter/archive/2004/12/01/273127.aspx

它是纯粹的.NET - 不依赖于第三方库。

现在给它一个角色......

答案 2 :(得分:8)

据我所知,您无法在VSTO中直接创建UDF。

参见Paul Stubbs的文章How to create Excel UDFs in VSTO managed code,他使用VBA加载项来公开VBA UDF,后者又调用用VSTO编写的托管UDF。

但是,不使用VSTO时,可以使用托管代码创建UDF。请参阅Eric Carter的文章Writing user defined functions for Excel in .NET,了解如何执行此操作。

至于VSTO的执行速度,我认为你会发现几乎所有任务都很好。然而,通过细胞循环,这已经是Excel的弱点,可能会非常缓慢,这取决于你正在做什么。尝试尽可能批量执行。例如,不是逐个循环遍历单元格,而是从区域返回二维值数组,处理数组,然后将其传递回范围。

为了演示,以下内容将返回一个区域的二维值数组,处理这些值,然后将结果数组一次性传回原始区域:

Excel.Range rng = myWorksheet.get_Range("A1:D4", Type.Missing);

//Get a 2D Array of values from the range in one shot:
object[,] myArray = (object[,])rng.get_Value(Type.Missing);

// Process 'myArray' however you want here.
// Note that the Array returned from Excel is base 1, not base 0.
// To be safe, use GetLowerBound() and GetUpperBound:
for (int row = myArray.GetLowerBound(0); row <= myArray.GetUpperBound(0); row++)
{
    for (int column = myArray.GetLowerBound(1); column <= myArray.GetUpperBound(1); column++)
    {
        if (myArray[row, column] is double)
        {
            myArray[row, column] = (double)myArray[row, column] * 2;
        }
    }
}

// Pass back the results in one shot:
rng.set_Value(Type.Missing, myArray);

希望这有帮助!

麦克

答案 3 :(得分:0)

我发现效果很好的是将UDF保留为VB模块,以避免COM对象出现问题。

我已经运行了大量的C#代码,当我准备构建版本时,我会执行以下操作:
1.添加模块:
开发人员[Excel中的选项卡] | Visual Basic - &gt;项目窗口,右键单击,插入模块
- 这里只是复制/粘贴VB代码 2.包括相应的参考库(同一VB窗口中的工具)
3.将Excel文件另存为.xlsm(即启用宏)

然后,您可以删除.xlsx文件。

我所做的是压缩整个目录(例如,“发布”)并将其发送给我们的用户。