繁体   English   中英

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

[英]excel vba preserve original value if UDF formula fails

在单个单元格中,我有一个引用 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! ?

PS 我对 VBA 还很陌生,所以我在这里可能遗漏了一些明显的东西。

您可以简单地使用Application.Caller.Text而不是Application.Caller.Value来返回单元格的原始文本。 这样做的一个缺点是单元格的值,无论类型如何,都将被转换为字符串。 根据引用Application.Caller单元格的其他单元格/公式(即,如果您希望“OtherWorkbook”返回数字而不是字符串),您可能必须使用=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

这样的事情怎么样:

' 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不可用时将其用作后备。

我找到了一种方法:

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM