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

我想要做的是使用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 ///  /// Required method for Designer support - do not modify /// the contents of this method with the code editor. ///  private void InternalStartup() { this.Startup += new System.EventHandler(ThisAddIn_Startup); this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown); } #endregion } } 

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

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

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

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

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

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

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

暴露UDF的.dna文件如下所示:

  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; } }  

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

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

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

它是纯.NET – 不依赖于第三方库。

现在给它一个洞穴……

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

请参阅Paul Stubbs的文章如何在VSTO托管代码中创建Excel UDF,其中他使用VBA加载项来公开VBA UDF,后者又调用VSTO编写的托管UDF。

但是,不使用VSTO时,可以使用托管代码创建UDF。 有关如何执行此操作,请参阅Eric Carter的文章为.NET中的Excel编写用户定义的函数 。

至于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); 

希望这可以帮助!

麦克风

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

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

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

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