Как легко создать Excel UDF с проектом надстройки VSTO

Я пытаюсь создать пользовательские функции (UDF) для Excel, используя тип проекта VSTO C # «Надстройка Excel 2007» (поскольку я просто хочу создать некоторые общие 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), я вижу свою надстройку в списке (который установлен на «Загрузить при запуске»). Но вот моя проблема: когда я пытаюсь вызвать свой UDF из встроенного Excel, Excel не может найти метод!

Я считаю неправильным то, что я должен пометить свой метод как UDF Excel (используя квадратные скобки - как, например, при кодировании веб-сервисов -> «[WebService]»). Но мне не удалось отследить этот тег (и поскольку я совсем не уверен, верна ли моя догадка), поэтому я решил обратиться к вам, прекрасные люди, здесь, в SO.

Итак, мой вопрос в основном таков: откуда я нахожусь со своим кодом, есть ли простой способ сделать мой UDF доступным для Excel? Если да, то как?

Я действительно хотел бы остаться в рамках типов проектов VSTO (надстройка, рабочая книга, шаблон), поскольку моя общая цель для моего текущего проекта - установить, работает ли выполнение UDF C # с VS2010 / Excel2007 с приемлемой скоростью. Чтобы проверить это, я работаю над Windows7RC и VS2010 beta1.


person Community    schedule 05.06.2009    source источник


Ответы (4)


VSTO не поддерживает создание файлов UDF Excel. Надстройки автоматизации могут быть созданы в .Net, и, похоже, это одобренный Microsoft способ сделать это.

Вам следует взглянуть на ExcelDna - http://www.codeplex.com/exceldna. ExcelDna позволяет управляемым сборкам предоставлять в Excel определяемые пользователем функции (UDF) и макросы через собственный интерфейс .xll. У проекта открытый исходный код, и его можно свободно использовать в коммерческих целях. И вы обнаружите, что производительность вашей UDF на основе .Net аналогична производительности собственных надстроек .xll для Excel. Поддерживаются такие функции Excel 2007, как большой лист, длинные строки Unicode и многопоточный пересчет.

С ExcelDna ваша функция, указанная выше, будет доступна в Excel без VSTO - вы можете поместить код в XML-файл .dna или скомпилировать его в .dll.

Файл .dna, раскрывающий ваш UDF, будет выглядеть так:

<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, а затем добавить пакет ExcelDna.AddIn из NuGet. Это делает надстройку для начинающих - просто вставьте свой код и нажмите F5 для запуска.

person Govert    schedule 12.06.2009

Похоже, у Эрика Картера есть победитель:

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

Это чистый .NET - никакой зависимости от сторонних библиотек.

Даю капу сейчас ...

person harvest316    schedule 09.06.2011
comment
Этот ответ должен быть выше ИМХО. Отсутствие 3D-библиотек и очень мало шаблонов - большие плюсы. - person Sebastiaan; 22.04.2017
comment
ссылка не работает - person AgostinoX; 02.07.2020
comment
Я полагаю, что это статья, на которую ссылается @ урожай316. docs.microsoft.com/ ru-ru / archive / blogs / eric_carter /. - person maoyang; 30.11.2020

Насколько мне известно, вы не можете напрямую создавать UDF в VSTO.

См. Статью Пола Стаббса Как создавать UDF Excel в управляемом коде VSTO, где он использует надстройку VBA для предоставления UDF VBA, которые, в свою очередь, вызывают его управляемые UDF, написанные на VSTO.

Однако вы можете использовать управляемый код для создания UDF, когда не используете VSTO. См. Статью Эрика Картера Написание пользовательских функций для Excel в .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);

Надеюсь это поможет!

Майк

person Mike Rosenblum    schedule 07.06.2009

Я обнаружил, что хорошо работает, так это сохранить UDF как модуль VB, чтобы избежать проблем с COM-объектами.

У меня запущено огромное количество кода C #, и когда я готов к сборке релиза, я делаю следующее:
1. Добавляю модуль:
Разработчик [вкладка в Excel] | Visual Basic -> окно проекта, щелкните правой кнопкой мыши, вставьте модуль
- просто скопируйте / вставьте сюда код VB
2. Включите соответствующую справочную библиотеку (Инструменты в том же окне VB)
3. Сохраните Excel файл в формате .xlsm (т. е. с поддержкой макросов)

Затем вы можете удалить файл .xlsx.

Что я делаю, так это заархивирую весь каталог (например, «Release») и отправляю его нашим пользователям.

person Gary Huckabone    schedule 30.08.2013