如果UDF公式失败,则excel vba保留原始值

时间:2014-12-11 19:46:46

标签: excel vba excel-vba excel-formula

在单个单元格中,我有一个引用UDF的指定公式:

=getValueFromWorkbook("OtherWorkbook", 10)

getValueFromWorkbook UDF粗略地做了类似......

的事情
Function getValueFromWorkbook(workbookName As String, identifier As Integer) As Variant
  ' some magic is done to get the `worksheetName` and `cellRange`
  ' but for simplicity, we'll just stub them here...
  Dim worksheetName As String: worksheetName = "SomeWorkSheet"
  Dim cellRange As String: cellRange = "A1"
  getValueFromWorkbook = Workbooks("" & workbookName & ".xlsx").Worksheets(worksheetName).Range(cellRange).Value
End Function

这很有效,只要OtherWorkbook.xlsx是一个开放的工作簿,单元格就会获得正确的价值,世界也会感到高兴。

现在,如果我关闭OtherWorkbook.xlsx工作簿,事情就会继续有效,单元格值仍会反映出来。

但是,如果我删除行或执行导致Excel重新计算所有单元格值的其他操作,UDF将失败(因为引用的工作簿不再打开),从而导致可怕的#VALUE!

理想情况下,我希望保留原始(陈旧)值而不是返回错误,但我还没有想出办法。

我尝试过的......

Function getValueFromWorkbook(...) As Variant
  ...
  On Error Resume Next
    getValueFromWorkbook = ...
  If Err.Number <> 0 Then
    Err.Clear
    getValueFromWorkbook = Application.Caller.Value
  End If
End Function

但这会导致循环引用错误:

  

公式中的单元格引用参考公式的结果,创建循环引用。

但是,如果我将Application.Caller.Value更改为Application.Caller.Text,这有点有效,但它会以文本形式返回,但我会丢失原始值格式。

所以,长话短说,是否有办法保留原始链接值而不是返回垃圾#VALUE!

P.S。我对VBA很陌生,所以我可能会在这里找到一些显而易见的东西。

3 个答案:

答案 0 :(得分:0)

您只需使用Application.Caller.Text而非Application.Caller.Value即可返回单元格的原始文本。这样做的一个缺点是,无论 type ,单元格的值都将被转换为字符串。根据其他单元格/公式(即,如果您希望&#34; OtherWorkbook&#34;返回数字而不是字符串)引用Application.Caller单元格,您可能需要更新它们使用=VALUE()

只要您不尝试使用其中的值更新实际单元格,这将起作用。输入一个单元格后,Application.Caller变为循环引用,然后您将返回0;你应该能够删除其他行。

Function getValueFromWorkbook(...) As Variant
  Dim Org As String
  Org = Application.Caller.Text      

  ...
  On Error Resume Next
    getValueFromWorkbook = ...
  If Err.Number <> 0 Then
    Err.Clear
    getValueFromWorkbook = Org
  End If
End Function

答案 1 :(得分:0)

这样的事情怎么样:

' Globally available variable to cache the external value.
Public GlobalValue As Variant

Function getValueFromWorkbook(workbookName As String, identifier As Integer) As Variant
    ' some magic is done to get the `worksheetName` and `cellRange`
    ' but for simplicity, we'll just stub them here...
    Dim worksheetName As String: worksheetName = "SomeWorkSheet"
    Dim cellRange As String: cellRange = "A1"

    Dim returnValue As Variant

    ' Attempt to get from the external sheet.
    ' This will fail if it isn't available.
    On Error Resume Next
    returnValue = Workbooks(workbookName & ".xlsx").Worksheets(worksheetName).Range(cellRange).Value

    If Err = 0 Then
        ' No error, we retrieved the value from the external file.
        ' Set it locally for use when this value isn't available.
        GlobalValue = returnValue
    Else
        ' Error - the external sheet wasn't available.
        ' Use the local value.
        returnValue = GlobalValue
    End If

    ' Done with error trapping.
    On Error GoTo 0

    getValueFromWorkbook = returnValue

End Function

我们的想法是在本地缓存该值,并将其用作当workbookName不可用时的后备。

答案 2 :(得分:0)

我找到了一种方法:

假设您将用户定义函数 UDF 放入单元格 A1 中,并且在某些情况下希望它保留先前的值而无需重新计算。然后,在这种情况下,使此函数返回任何错误值:UDF = CVErr(xlErrNull)并按以下方式修改您的 A1 公式:=IFERROR(UDF(...); A1)

这可能会产生循环引用的警告-您可以通过在文件->选项->公式中启用循环引用并使用此设置保存文件来摆脱它。