2010-04-19 98 views
3

我有運行的子程序內發現環路時常規使用Application.Evaluate或ActiveSheet.Evaluate方法叫一些問題。例如,在下面的代碼中,我定義了一個子例程FindSub(),它在工作表中搜索字符串「xxx」。例程CallSub()使用標準的Call語句和Evaluate調用FindSub()例程。爲什麼從Evaluate調用VBA Find循環失敗?

當我運行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 
+0

有關於.Evaluate下這個問題的侷限性了一些有趣的討論:http://stackoverflow.com/questions/2611929/stop-vba-evaluate-from-calling-target-function-twice – 2010-04-19 14:35:43

+0

@Richard ,這也是這個問題的作者=) – 2010-04-19 15:03:45

+0

@Joel,Ooops。這不是我很注意的。謝謝:)不過,對於其他人來說,回顧一下它是否是一個很好的問題。評估奇怪。 – 2010-04-19 15:38:27

回答

1

的原因是最有可能的評估是看到你的函數的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來運行圍繞表單運行的函數,所以從某種意義上說,這是未定義的行爲,不能被視爲一個錯誤。評估是爲了運行一個公式,其中所有單元格引用都在公式中明確地映射出來。我自己的理論是Find Next不起作用,因爲您正在嘗試使用不是活動單元格的單元格引用,並且Evaluate正試圖阻止這種非法活動。
  3. 你的錯誤。在Loop Until行上,處理Or測試。麻煩的是,如果rngFoundCellNothing,第二個測試會拋出一個錯誤; VBA正在嘗試處理完整表達式,並且在此情況下無法評估rngFoundCell.Address。當作爲UDF運行時(即在Evaluate內),代碼將立即退出而不會出現錯誤對話框。這就是爲什麼你在Evaluate中看不到「完成」的原因。
+0

我只是想說這個,但我仍然困惑的是OP正在評估一個Sub,不要以爲會工作。與'.Find'相同。我只是把它記錄下來,看看那些沒有文檔的「評估」...... – jtolle 2010-04-19 15:24:51

+0

這確實犯了一個UDF的罪過,當然,這是與幕後的其他單元一起玩耍(不管你是否改變它們,它會打破依賴關係樹)。 Find發現奇怪的是Find沒有受到傷害。可能不應該有。 – 2010-04-19 15:33:06

+0

非常翔實的跟進...謝謝! – jtolle 2010-04-20 16:49:54

0

下面應該工作:

Call FindSub 
Call Application.Run("FindSub") 

對我來說.Evaluate失敗&什麼都不做。

如果我使用Call Application.Run("FindSub()")(與parens),我會看到與您一樣的行爲(「部分」第二次調用)。

您也可以嘗試Application.Evaluate "FindSub"