如何不挂Excel?

How to not hang Excel?

我遇到这个问题,我的易失性宏类型 UDF 设置调用单元格旁边的几个单元格的值,除非在 sheet 中使用两次(或更多次),否则工作正常:Excel 状态栏开始闪烁 "Calculating...".

我不是真正的挂起,而是大量的重新计算:示例函数中的计数器是在没有实际挂起的情况下绘制的。

此外,我不确定是否使用可变 UDF,因为我需要自动重新计算,但仅在输入更改时进行,而不是持续轮询。

我确实制作了一个具有三个功能的示例模块:

我认为这与 ExcelAsyncUtil.QueueAsMacro 的工作方式和线程安全有关,但我在这里感到困惑。

Imports ExcelDna.Integration
Imports ExcelDna.Integration.XlCall

Public Module Example

    <ExcelFunction(IsMacroType:=True, IsVolatile:=True)>
    Public Function VolatileNyanCat() As String

        Dim caller = CType(XlCall.Excel(XlCall.xlfCaller), ExcelReference)
        Dim NyanCat(,) As String = {{"Nyan", "Cat"}}

        Dim nc As New ExcelReference(caller.RowFirst + 1, caller.RowLast + 1,
                                     caller.ColumnFirst, caller.ColumnLast + 1,
                                     caller.SheetId)

        Static nyy As Integer = 1

        ExcelAsyncUtil.QueueAsMacro(Sub()
                                        nyy += 1
                                        nc.SetValue(NyanCat)
                                    End Sub)
        Return "NYA! x " + CStr(nyy)
    End Function

    <ExcelFunction(IsMacroType:=True)>
    Public Function NonVolatileOneNyanCat() As String

        Dim caller = CType(XlCall.Excel(XlCall.xlfCaller), ExcelReference)
        Dim NyanCat(,) As String = {{"Nyan", "Cat"}}

        Dim nc As New ExcelReference(caller.RowFirst + 1, caller.RowLast + 1,
                                     caller.ColumnFirst, caller.ColumnLast + 1,
                                     caller.SheetId)

        Static nyy As Integer = 1

        ExcelAsyncUtil.QueueAsMacro(Sub()
                                        nyy += 1
                                        nc.SetValue(NyanCat)
                                    End Sub)
        Return "NYA! x " + CStr(nyy)
    End Function

    <ExcelFunction(IsMacroType:=True, IsVolatile:=True)>
    Public Function HangNyanCat() As String

        Dim caller = CType(XlCall.Excel(XlCall.xlfCaller), ExcelReference)
        Dim nyan(,) As String = {{"Nyan"}} : Dim cat(,) As String = {{"Cat"}}

        Dim n As New ExcelReference(caller.RowFirst + 1, caller.RowLast + 1,
                                    caller.ColumnFirst, caller.ColumnLast,
                                    caller.SheetId)

        Dim c As New ExcelReference(caller.RowFirst + 1, caller.RowLast + 1,
                                    caller.ColumnFirst + 1, caller.ColumnLast + 1,
                                    caller.SheetId)

        Static nyy As Integer = 1

        ExcelAsyncUtil.QueueAsMacro(Sub()
                                        n.SetValue(nyan)
                                        c.SetValue(cat)
                                        nyy += 1
                                    End Sub)
        Return "NYA! x " + CStr(nyy)
    End Function
End Module

ExcelAsyncUtil.QueueAsMacro 运行 尽快输入代码 - 在本例中为计算完成时。但是你 运行 的宏在 sheet 上设置了一些值,所以 volatile 函数将再次计算。它排队一个新的宏来设置一些单元格......等等所以一切似乎都按预期工作。

不建议从 UDF 内部设置其他单元格,Excel 会阻止 - 这就是为什么您必须通过奇怪的宏路径。如果你能重组你的函数,使其没有这些副作用,Excel 会变得更快乐。