从Evaluate调用时,为什么VBA Find循环失败?

时间:2010-04-19 14:19:09

标签: excel vba

当使用Application.Evaluate或ActiveSheet.Evaluate方法调用例程时,我在子例程中运行find循环时遇到一些问题。例如,在下面的代码中,我定义了一个子程序FindSub(),它在工作表中搜索字符串“xxx”。例程CallSub()使用标准Call语句和Evaluate来调用FindSub()例程。

当我运行Call FindSub时,一切都会按预期工作:每个匹配的地址都会打印到即时窗口,当代码完成时我们会收到“完成”的最终消息。但是,当我执行Application.Evaluate“FindSub()”时,只打印出第一个匹配的地址,并且我们永远不会到达“已完成”消息。换句话说,在Cells.FindNext行之后遇到错误,因为循环尝试评估它是否应该继续,并且程序执行停止而不会打印任何运行时错误。

我希望调用FindSub和Application.Evaluate“FindSub()”在这种情况下产生相同的结果。有人可以解释为什么他们不这样做,如果可能的话,还有办法解决这个问题吗?感谢。

注意:在这个例子中,我显然不需要使用Evaluate。这个版本被简化为只关注我在更复杂的情况下遇到的特定问题。

Sub CallSub()
    Call FindSub
    Application.Evaluate "FindSub()"
End Sub

Sub FindSub()
    Dim rngFoundCell As Range
    Dim rngFirstCell As Range

    Set rngFoundCell = Cells.Find(What:="xxx", after:=ActiveCell, LookIn:=xlValues, _
        LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
        MatchCase:=False, SearchFormat:=False)

    If Not rngFoundCell Is Nothing Then
        Set rngFirstCell = rngFoundCell
        Do
            Debug.Print rngFoundCell.Address
            Set rngFoundCell = Cells.FindNext(after:=rngFoundCell)
        Loop Until (rngFoundCell Is Nothing) Or (rngFoundCell.Address = rngFirstCell.Address)
    End If

    Debug.Print "Finished up"
End Sub

2 个答案:

答案 0 :(得分:1)

原因很可能是Evaluate将您的功能视为UDF - 就像从工作表公式中调用它一样。 UDF对他们可以做的事情有很大的限制 - 特别是没有设置属性或调用其他功能 - 我想这里的一些东西已经违反了这些限制,尽管我无法完全区分这里做了什么。

在UDF中,由于不允许工作表公式抛出VB错误,因此会无提示地吞下错误。 (如果公式错误不断地抛出VB对话框,它会破坏Excel用户界面)

有关UDF限制的详细信息,请参阅http://support.microsoft.com/kb/170787

编辑:好的,这里有一些关于您的问题的说明,我知道您的代码在评估过程中默默地出错。使用此代码:

Sub FindSub()
    Dim rngFoundCell As Range
    Dim rngFirstCell As Range

    Set rngFoundCell = Cells.Find(What:="xxx", after:=ActiveCell, LookIn:=xlValues, _
        LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
        MatchCase:=False, SearchFormat:=False)

    If Not rngFoundCell Is Nothing Then
        Set rngFirstCell = rngFoundCell
        Do
            Debug.Print "FOUND: " & rngFoundCell.Address
            Set rngFoundCell = Cells.FindNext(after:=rngFoundCell)
            Debug.Print "FIND NEXT: " & IIf(rngFoundCell Is Nothing, " NOTHING", " SOMETHING")
        Loop Until (rngFoundCell Is Nothing) Or (rngFoundCell.Address = rngFirstCell.Address)
        Debug.Print "ESCAPED LOOP"
    End If

    Debug.Print "Finished up"
End Sub

我在即时窗口中得到以下输出:

findsub
FOUND: $G$6
FIND NEXT:  SOMETHING
FOUND: $D$11
FIND NEXT:  SOMETHING
ESCAPED LOOP
Finished up

太好了。但是:

callsub
FOUND: $G$6
FIND NEXT:  SOMETHING
FOUND: $D$11
FIND NEXT:  SOMETHING
ESCAPED LOOP
Finished up
FOUND: $G$6
FIND NEXT:  NOTHING

这里有三点需要注意,至少在我运行它时。

  1. 该函数被调用两次。这是Evaluate的一个已知问题,它与Excel如何处理工作表上的计算有关。这就是为什么不应该在记录数据的函数上使用Evaluate的原因 - 因为它可以在单个Evaluate中多次调用。
  2. 在第二个循环中,“查找下一个”无法找到另一个单元格。这是一个谜,但是Evaluate不应该用于运行在工作表中运行的函数,所以在某种程度上,这是未定义的行为,并不能真正被视为错误。 Evaluate用于运行公式,其中所有单元格引用都在公式中显式映射。我自己的理论是Find Next不起作用,因为你试图使用一个不是活动单元格的单元格引用,而Evaluate试图杀死那种非法活动。
  3. 你的错误。在Loop Until行,您处理或测试。问题是,如果rngFoundCellNothing,则第二次测试会抛出错误; VBA正在尝试处理完整表达式,在这种情况下无法评估rngFoundCell.Address。当作为UDF运行时(即在Evaluate中),代码将立即退出而没有错误对话框。这就是为什么你没有在评估中看到“完成”的原因。

答案 1 :(得分:0)

以下内容应该有效:

Call FindSub
Call Application.Run("FindSub") 

对我而言.Evaluate失败&什么也没做。

如果我使用Call Application.Run("FindSub()")(使用parens),我会看到与您相同的行为(“部分”第二次调用)。

您也可以尝试Application.Evaluate "FindSub"