Как написать массив в определяемой пользователем функции Excel

У меня есть надстройка Excel, созданная с использованием Excel-DNA, и UDF как часть надстройки Excel. Допустим, функция находится в ячейке A10, и я собираюсь удалить столбец Z. Я обнаружил, что это действие вызывает повторное выполнение функции.

Есть ли способ предотвратить такое поведение? Это связано с моделью расчета или волатильностью?

ИЗМЕНИТЬ 1

Я использую следующий код для реализации поведения, подобного функциональности Bloomberg BDH, т. е. функция записывается в первой ячейке, а остальная часть массива записывается через поток.

У меня есть 2 проблемы:

  1. Я не могу определить, как должно мигать сообщение в ячейке, где написана функция. Например, если функция выполняется в ячейке A1, сообщение «Обработка...» отображается до тех пор, пока значение ячейки не будет записано.
  2. При этой реализации происходит пересчет функций.

Я видел реализации, в которых пункты 1 и 2 выше работают хорошо, но не могу определить, как это сделать. У кого-нибудь есть идеи

public class ArrayWriter
{
    #region Methods

    #region WriteArray
    [ExcelFunction(IsHidden=true)]
    public object WriteArray(object[,] arrayToWrite)
    {
        object caller = null;
        object formula = null;
        AddInFacade facade;

        // if not in a function
        if (!ExcelDnaUtil.IsInFunctionWizard())
        {
            facade = new AddInFacade();

            if (arrayToWrite != null)
            {
                // if writing more than one cell, use threads
                if (arrayToWrite.GetLength(0) > 1 || arrayToWrite.GetLength(1) > 1)
                {
                    var xlApp = ExcelDnaUtil.Application as Application;
                    Type xlAppType = xlApp.GetType();

                    caller = xlApp.Caller;
                    //caller = xlAppType.InvokeMember("ActiveCell", BindingFlags.GetProperty, null, xlApp, null);
                    formula = xlAppType.InvokeMember("FormulaR1C1Local", BindingFlags.GetProperty, null, caller, null);

                    // create instance of ObjectForThread and set all properties of the class
                    ObjectForThread threadObject = new ObjectForThread()
                    {
                        xlRef = caller,
                        value = arrayToWrite,
                    };

                    // create a new thread calling the method WriteFromThread and start the thread
                    Thread threadWriter = new Thread(() => WriteFromThread(threadObject));
                    threadWriter.Start();
                }
                else
                {
                    facade.SetMouseCursor(XlMousePointer.xlDefault);
                }
            }
            else
            {
                arrayToWrite = new object[1, 1];
                arrayToWrite[0, 0] = "No data was returned.";
                facade.SetMouseCursor(XlMousePointer.xlDefault);
            }
        }

        return arrayToWrite[0,0];
    }
    #endregion

    #region WriteFromThread
    private void WriteFromThread(Object boxedThreadObject)
    {
        AddInFacade facade = new AddInFacade();

        ObjectForThread unboxedThreadObject = (ObjectForThread)boxedThreadObject;
        Object cellBelow;

        Type typeCellReference = unboxedThreadObject.xlRef.GetType();

        try
        {
            for (int i = 0; i < unboxedThreadObject.value.GetLength(0); i++)
            {
                for (int j = 0; j < unboxedThreadObject.value.GetLength(1); j++)
                {
                    // do not write the first cell as this is what is returned by the function
                    if (i > 0 || j > 0)
                    {
                        cellBelow = typeCellReference.InvokeMember("Offset", BindingFlags.GetProperty, null, unboxedThreadObject.xlRef, new object[] { i, j });
                        typeCellReference.InvokeMember("Value", BindingFlags.SetProperty, null, cellBelow, new[] { Type.Missing, unboxedThreadObject.value[i, j] });
                    }
                }
            }
        }
        catch(Exception ex)
        {
            string szError = ex.Message;
        }
        finally
        {
            // attempt to kill all COM references
            unboxedThreadObject.xlRef = null;
            unboxedThreadObject.value = null;

            //Set the mouse cursor to the default cursor since the entire array has now been written
            facade.SetMouseCursor(XlMousePointer.xlDefault);

            unboxedThreadObject = null;
            cellBelow = null;
            facade = null;
        }
    }
    #endregion

    #endregion

    #region ObjectForThread Class
    public class ObjectForThread
    {
        public object xlRef { get; set; }
        public object[,] value { get; set; }
    }
    #endregion
}

person Lee Z    schedule 04.12.2013    source источник


Ответы (1)


Единственный способ изменить это поведение — изменить Application.Calculation собственность. Но ты не хочешь этого делать. Это свойство должно быть изменено только на мгновение, а затем должно быть сброшено до предыдущего значения. В противном случае вы пишете надстройку, которая плохо работает в общей песочнице.

person Michael Gunter    schedule 04.12.2013