Excel VBA宏似乎在进行异步循环

人工智能 2026-07-11

我有一个绑定到特定工作表的VBA宏,其结构如下(子程序开始处对所有变量都进行了Dim的声明)。紧随 'Debugging' 的行是我在排查循环怪异行为时添加的调试代码。

For Each checkKey In checkValues.Keys
  ' The keys are cell addresses in the active sheet. Generally, a vertical
  ' stack of cells ordered from top to bottom
  newValue = Range(checkKey).value

  If checkValues(checkKey) <> newValue Then
    ' Update the value
    checkValues(checkKey) = newValue

    ' Debugging
    Range(checkKey).Offset(0, 6) = 0

    ' Now perform some calculations
    someValue = SomeFunction(newValue)

    ' Debugging
    Range(checkKey).Offset(0, 6) = 1

    ' Fill in the results of the calculation
    Range(checkKey).Offset(0, 1).value = someValue("Part1")
    Range(checkKey).Offset(0, 2).value = someValue("Part2")

    ' Debugging
    Range(checkKey).Offset(0, 6) = 2

    ' Perform some more calculations
    anotherValue = AnotherFunctin(newValue)

    ' Debugging
    Range(checkKey).Offset(0, 6) = 3

    ' Fill in the results of the calculation
    Range(checkKey).Offset(0, 3).value = anotherValue("Part1")
    Range(checkKey).Offset(0, 4).value = anotherValue("Part2")

    ' Debugging
    Range(checkKey).Offset(0, 6) = 4
  End If
Next checkKey

我看到的情况是:假设checkValues列表中有10个单元格,形成一个连续的纵向块。我本来预期看到的是,顶端那个单元格右侧的单元格都会按照计算更新,看着“debug cell”的计数从0 增到4。然后是下一行往下的右侧单元格,再下一行往下的右侧单元格,依此类推。

但实际并非如此。相反,整组“debug cells”都被设为零,好像循环只执行了整段循环的前几行。随后,数值单元格开始缓慢更新(它们的计算相对较长),从底部向上更新。每处理一行时,其对应的“debug cell”也相应地从1 继续数到4。

几乎可以说,每次循环迭代时,VBA引擎都会执行到某个点就停下来,把该次迭代的状态压入一个栈中,然后进入下一次迭代。之后它再从栈中逐个取出,按相反的顺序完成。

有没有人遇到过这样的行为?有没有办法禁用这种行为,让循环在进入下一次迭代之前完成当前的每一次迭代?

解决方案

我终于搞清楚了发生了什么:问题中的代码是由工作表上的“更改”事件触发的,因此只要某个单元格发生变化,它就必须检查自己关心的单元格是否受到影响。

背景说明:它不能使用Target参数,因为它关心的单元格包含公式。对于包含公式的单元格,其结果变化并不会触发更改事件——只有你直接改变该单元格的内容时才会触发。

对change事件的早期研究(AI——去想想看!)让我以为它只在手动修改时显式触发。所以,当事件代码本身修改一个单元格时,这本不应该触发change事件。

结果证明那是不正确的。无论是手动还是通过脚本,只要单元格的内容被修改,change事件就会被触发。

我的子程序中的第一条对单元格的修改语句(向“debug cell”写入0)触发了一个改变事件,使子例程重新进入,等等。这就是为什么最初所有的“debug cells”都回到初始值0。随后,最后一个子例程(确实有点像一个栈)得以完成,依次让倒数第二个完成,然后再前一个,直到回到第一个。

解决办法是在子例程执行期间禁用事件触发,然后在结束后重新启用它们。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章