在一张纸上重新计算Excel VBAfunction会中断其他纸张

我做了一个函数来计算给定月份中的项目数量。

列A是月份,列B是该月份的项目数量。

单元格B1有:

=countItems(A1) 

Excel数据:

Excel数据

码:

 Function countItems(month) Application.Volatile Dim count As Integer If Not (month = 0) Then count = 0 Do While Not (Cells(month.row + count + 1, 3) = 0) count = count + 1 Loop countItems = count Else countItems = "" End If End Function 

我把公式从B1下拉到B500,每个月都能正常工作。 如果相应的A单元格中没有月份,则该公式将不会返回任何内容。

在同样结构化的数据集上,我有多个工作表使用相同的公式。 无论何时B列中的值更新为此工作表1,其他工作表也将更改。 但是,工作表2将使用工作表1中的列C进行更新。

如果我重新计算Sheet 2,Sheet 1将使用Sheet 2中的Column C进行更新。

该函数通过检查列C中可以读取多less的元素来查找给定月份中的项目数量,之后它find空白单元格,表示该月份结束。 工作表2在第一个月有1个项目,但由于工作表1有3个项目(计数行1到3并停在行4),它仍然会返回3。 工作表2的第二个月从第3行开始。但由于函数正在从工作表1中读取C列, 所以在计数了1个项目(计数第3行并停在第4行)之后它将进入空白单元格 。 因此,无论表单2第2个月有多less项目,都会返回1。

该函数始终使用正确的列A,并且只在A列中显示一个数字,其中列A中有date。

结果是只有一张纸可以有正确的值,这样做会扰乱其他纸张。

目前我无法解决这个问题,因为我是VBA的新手。

我曾经想过让所有的函数的单元格引用都包含一个自引用到当前单元格的表单,但是我不知道该怎么做,我不知道它是否可行。

编辑:我不能这样工作,但与相对单元格位置的Application.Caller.Offset()作为解决scheme。 我仍然想知道是否有一种方法可以使用绝对的细胞位置。

这些表没有分组在一起。

这是因为传递给函数的范围与作为函数的“调用者”范围“感觉”的范围之间存在“时空转换”

您可以通过如下修改function代码来查看此行为

 Function countItems(month) Application.Volatile Dim count As Integer Dim r As Range Dim p As Variant, a As Variant Set r = Application.Caller '<~~ retrieve the actual "calling cell" of the current function "instance" p = r.Parent.Name a = r.Address MsgBox p & " vs " & month.Parent.Name & vbCrLf & a & " vs " & month.Address '<~~ compare the function "calling cell" vs the "passed cell" If Not (month = 0) Then count = 0 Do While Not (Cells(month.Row + count + 1, 3) = 0) count = count + 1 Loop countItems = count Else countItems = "" End If End Function 

你会看到msgboxs的提示,显示了函数“调用单元格”和“传递的单元格”地址和/或表单之间的区别

所以要避免这种行为,你可以依靠“只有调用范围”,如下所示:

 Option Explicit Function countItems(month) Application.Volatile Dim r As Range Set r = Application.Caller '<~~ retrieve the actual "calling cell" of the current function "instance" 'the "calling cell" is the one with the called function in its formula, ie in column "B" as per your data structure. then ... If Not IsEmpty(r.Offset(, -1)) Then '<~~ ... the column with dates are one column to the left, and ... Do While Not IsEmpty(r.Offset(countItems + 1, 1)) '<~~ ... the values to be checked for are one column to the right countItems = countItems + 1 Loop End If End Function