如何在 Excel 用户定义函数中写入数组
Posted
技术标签:
【中文标题】如何在 Excel 用户定义函数中写入数组【英文标题】:How to write array in Excel User Defined Function 【发布时间】:2013-12-04 15:44:44 【问题描述】:我有一个使用 Excel-DNA 创建的 Excel 插件,并且有一个 UDF 作为 Excel 插件的一部分。假设函数在单元格 A10 中,我去删除 Z 列。我发现此操作会导致函数再次执行。
有没有办法防止这种行为发生?这与计算模型或波动率有关吗?
编辑 1
我正在使用以下代码来实现类似于 Bloomberg BDH 功能的行为 - 即,该函数写入第一个单元格,而数组的其余部分通过线程写入。
我有两个问题:
-
我无法确定如何在写入函数的单元格中显示消息。例如,如果函数在单元格 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
【问题讨论】:
【参考方案1】:更改此行为的唯一方法是更改Application.Calculation 属性。但你不想那样做。此属性只能暂时更改,之后应重置为以前的值。否则,您正在编写的插件在共享沙盒中无法正常运行。
【讨论】:
以上是关于如何在 Excel 用户定义函数中写入数组的主要内容,如果未能解决你的问题,请参考以下文章
如何在所有excel中使用用户定义的函数而不需要额外的操作?