Как легко создать Excel UDF с проектом надстройки VSTO - PullRequest
19 голосов
/ 05 июня 2009

То, что я пытаюсь сделать, - это создать пользовательские функции (UDF) для Excel, используя тип проекта CST «Надстройка 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 (Add-In, Workbook, Template), поскольку моя общая цель для моего текущего проекта - установить, работает ли выполнение C # UDF с VS2010 / Excel2007 на приемлемом уровне. скорость. Чтобы проверить это, я работаю на Windows7RC и на бета-версии VS2010.

Ответы [ 4 ]

19 голосов
/ 12 июня 2009

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

Вы должны взглянуть на ExcelDna - http://www.codeplex.com/exceldna. ExcelDna позволяет управляемым сборкам предоставлять пользовательские функции (UDF) и макросы в Excel через собственный интерфейс .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 для запуска.

9 голосов
/ 09 июня 2011

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

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

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

Давай это сейчас ...

8 голосов
/ 07 июня 2009

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

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

Однако вы можете использовать управляемый код для создания пользовательских функций, если не используете 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);

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

Mike

0 голосов
/ 30 августа 2013

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

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

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

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

...