У меня есть надстройка Excel, созданная с использованием Excel-DNA, и UDF как часть надстройки Excel. Допустим, функция находится в ячейке A10, и я собираюсь удалить столбец Z. Я обнаружил, что это действие вызывает повторное выполнение функции.
Есть ли способ предотвратить такое поведение? Это связано с моделью расчета или волатильностью?
ИЗМЕНИТЬ 1
Я использую следующий код для реализации поведения, подобного функциональности Bloomberg BDH, т. е. функция записывается в первой ячейке, а остальная часть массива записывается через поток.
У меня есть 2 проблемы:
- Я не могу определить, как должно мигать сообщение в ячейке, где написана функция. Например, если функция выполняется в ячейке A1, сообщение «Обработка...» отображается до тех пор, пока значение ячейки не будет записано.
- При этой реализации происходит пересчет функций.
Я видел реализации, в которых пункты 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
}