Excel正在计算一个带有VBA函数的公式作为错误,除非它被重新input

我有一个简单的if语句在工作表中设置if条件是VBA用户定义函数:

Function CellIsFormula(ByRef rng) CellIsFormula = rng(1).HasFormula End Function 

这个function似乎工作正常:

评估1评估2

但由于某种原因,我不明白,单元格正在评估一个错误。 更糟糕的是,在评估公式时,excel将错误归因于不会产生错误的计算步骤:

评估4评估5评估6

最重要的是,如果我简单地重新input公式,或强制重新计算( Ctrl + Alt + F9 ),那么这个公式没有问题!

重新输入公式计算工作

我已经尝试通过将Application.Volatile添加到函数代码中来使公式volatile,但是它没有改变任何东西。 其他方法刷新计算,如设置计算手动,然后回到自动,隐藏“重新计算表”,或者只是使用F9Ctrl + F9不起作用,只有重新input公式或Ctrl + Alt + F9将导致函数重新正确计算。

更改if语句中引用的单元格之一不会解决问题, 更改由“CellIsFormula”函数引用的单元格确实解决了该问题。 每次单张被重新打开,但错误又回来了。

我发现了确切的问题,但是我想给大家投票,试图帮助我解决这个问题,并给GSerg一个信誉,因为虽然我并不是完全没有运气,但是他的build议是死的

Excel确实希望在某些计算阶段使某个范围的某些属性不可用。

很好找GSerg。

问题出在事件处理程序上 。 工作簿包含一系列事件处理程序,如Workbook_Open,Worksheet_Change等等。现在,这些事件处理程序所采取的某个操作将导致工作簿中的某些单元格重新计算。 如果Excel在macros运行时触发重新计算,则包含此UDF的任何单元格都将导致错误。 这是因为某些原因,在VBA触发重新计算过程中, .HasFormula属性不可用 ,就像@GSerg所说: 属性不可用

据推测,接下来的一点是Excel的一个疏忽,但是一旦macros完成运行,如果重新计算完成,导致错误,因为UDFs运行不正常,excel将不会尝试再次运行UDF。 产生的错误值将被假定为调用的返回值,除非认为该UDF的参数已更改,否则不会更改。 Excel将caching用户定义函数调用的结果,直到其参数引用的单元格被更改。

这就是为什么单步执行“评估公式”会显示所有工作到最后一步,而实际上并没有对最后一步进行评估,它只显示上次计算的电子表格中的值。

实际上有两种可能的解决scheme。 我发现的第一个解决scheme是在开始时禁用自动计算事件处理程序,然后重新启用它。 由于某些原因,即使一个macros正在运行的时间计算被设置回xlCalculationAutomatic,它将导致UDF被成功地重新评估,并且该属性是可用的。

第二个解决scheme,我喜欢,因为它可以防止这个意外再次发生,是使用不同的方法来检查一个公式:

 Function CellIsFormula(ByRef rng As Range) As Boolean CellIsFormula = Left(rng(1).Formula, 1) = "=" End Function 

.Formula属性永远不可用。 所以这个问题从来不会发生

我无法重现这个错误,但是:

  1. 签名应该是:

     Public Function CellIsFormula2(ByVal rng As Range) As Boolean CellIsFormula2 = rng.Cells(1).HasFormula End Function 
  2. Excel确实希望在某些计算阶段使某个范围的某些属性不可用。 我曾多次看到.Text属性突然不可用。 所以,如果改变签名不起作用,那么你可能是运气不好。

我认为你的问题是因为'HasFormula'属性返回一个变体,而不是一个布尔值。 如果范围有混合的公式和值,HasFormula将返回null。 加上你不把rng定义为Range对象,不指定输出types。 我build议一个这样的方法。 它可以被修改,很容易地返回一个布尔值。

 Public Function CellIsFormula(rng As Range) As String Application.Volatile Dim testVal As Variant testVal = rng.HasFormula 'HasFormula returns variant type 'testval is null if cells are mixed formulas and values If IsNull(testVal) Then testVal = "Mixed" End If Select Case testVal Case True CellIsFormula = "All Cells in Range Have formula" Case False CellIsFormula = "No Cells in Range Have formula" Case "Mixed" CellIsFormula = "Some Cells in Range Have formula" Case Else CellIsFormula = "Error" End Select End Function