C# 如何使用VSTO加载项项目轻松创建Excel自定义项

C# 如何使用VSTO加载项项目轻松创建Excel自定义项,c#,visual-studio-2010,vsto,excel-2007,C#,Visual Studio 2010,Vsto,Excel 2007,我正在尝试使用VSTO的C#“Excel2007Add-in”-项目类型为Excel创建用户定义函数(UDF)(因为我只想生成一些通用UDF)。由于我只是尝试学习基础知识(无论如何,在这个阶段),因此我的代码是这样的: using System; using System.Collections.Generic; using System.Text; using System.Xml.Linq; using Excel = Microsoft.Office.Interop.Excel; usin

我正在尝试使用VSTO的C#“Excel2007Add-in”-项目类型为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
    }
}
使用系统;
使用System.Collections.Generic;
使用系统文本;
使用System.Xml.Linq;
使用Excel=Microsoft.Office.Interop.Excel;
使用Office=Microsoft.Office.Core;
使用Microsoft.Office.Tools.Excel;
使用Microsoft.Office.Tools.Excel.Extensions;
使用System.Runtime.InteropServices;
命名空间ExcelAddIn1
{
公共部分类ThisAddIn
{
私有void ThisAddIn_启动(对象发送方,System.EventArgs e)
{}
私有void ThisAddIn_关闭(对象发送方,System.EventArgs e)
{}
//我的UDF
公共静态双Heronical(int a、int b、int c)
{
//第一次计算S=(a+b+c)/2
双S=(a+b+c)/2;
双面积=数学Sqrt(S*(S-a)*(S-b)*(S-c));
返回区;
}
#区域VSTO生成的代码
/// 
///设计器支持所需的方法-不修改
///此方法的内容与代码编辑器一起使用。
/// 
私有void InternalStartup()
{
this.Startup+=new System.EventHandler(ThisAddIn\u启动);
this.Shutdown+=new System.EventHandler(ThisAddIn\u Shutdown);
}            
#端区
}
}
它编译得很好,当我运行它时,Excel会弹出一个新的电子表格,当我查看“加载项”-列表(在Excel选项中)时,我可以在列表中看到我的加载项(设置为“启动时加载”)。但是我的问题来了,当我尝试从Excel中的with调用我的UDF时,Excel找不到该方法

我的想法是错误的,我必须将我的方法标记为一个Excel UDF(使用方括号–例如在编写WebService->“[WebService]”时所做的)。但是我无法跟踪这个标记(因为我根本不确定我的直觉是否正确)这就是为什么我决定在这里找你们这些优秀的人

所以我的问题基本上是——从我使用代码的角度来看,有没有简单的方法可以让我的UDF访问Excel?如果有,如何


我真的希望保持VSTO项目类型(外接程序、工作簿、模板),因为我当前项目的总体目标是确定使用VS2010/Excel2007执行C#UDF的速度是否可以接受。为了测试这一点,我正在使用Windows7RC和VS2010 beta1。据我所知,您不能在VSTO中直接创建UDF

请参阅Paul Stubbs的文章,其中他使用VBA外接程序公开VBA UDF,而VBA UDF反过来调用他在VSTO中编写的托管UDF

但是,当不使用VSTO时,您可以使用托管代码来创建UDF。请参阅Eric Carter关于如何做到这一点的文章

至于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);
Excel.Range rng=myWorksheet.get_Range(“A1:D4”,类型.缺失);
//一次从范围中获取二维值数组:
object[,]myArray=(object[,])rng.get_值(Type.Missing);
//在此处按您所需的方式处理“myArray”。
//请注意,从Excel返回的数组以1为基数,而不是以0为基数。
//为了安全起见,请使用GetLowerBound()和GetUpperBound:

对于(int row=myArray.GetLowerBound(0);rowVSTO不支持创建Excel UDF。可以在.Net中创建自动化加载项,这似乎是Microsoft批准的方法

您应该看看ExcelDna-。ExcelDna允许托管程序集公开用户定义函数(UDF)和宏通过本机.xll界面转换为Excel。该项目是开放源代码的,并免费允许商业使用。您会发现基于.Net的UDF的性能与用于Excel的本机.xll加载项类似。Excel 2007支持大工作表、长Unicode字符串和多线程重新计算等功能

使用ExcelDna,您上面发布的函数将在没有VSTO的情况下暴露于Excel中-您可以将to代码放入基于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>

使用制度;
利用ExcelDna进行整合;
公共类函数
{
[ExcelFunction(Description=“Calculate Stuff”,Category=“Cool Functions”)]
公共静态双Heronical(int a、int b、int c)
{
//第一次计算S=(a+b+c)/2
双S=(a+b+c)/2;
双面积=数学Sqrt(S*(S-a)*(S-b)*(S-c));
返回区;
}
}

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

看起来Eric Carter在这里有一个赢家:

它是纯.NET的,不依赖于第三方库


现在给它一个负担…

我发现,将UDF保留为VB模块可以很好地避免COM对象的问题

我已经运行了大量的C代码,当我准备好构建发行版时,我会执行以下操作:
1.添加模块:
开发者[标签页]