如果自定义项公式失败,excel vba将保留原始值

如果自定义项公式失败,excel vba将保留原始值,vba,excel,excel-formula,Vba,Excel,Excel Formula,在单个单元格中,我有一个引用自定义项的指定公式: =getValueFromWorkbook("OtherWorkbook", 10) GetValueFrom工作簿UDF大致执行以下操作 Function getValueFromWorkbook(workbookName As String, identifier As Integer) As Variant ' some magic is done to get the `worksheetName` and `cellRange`

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

=getValueFromWorkbook("OtherWorkbook", 10)
GetValueFrom工作簿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将失败,因为引用的工作簿不再打开,从而导致一个可怕的值

理想情况下,我希望这样做是为了保留原始的过时值,而不是返回错误,但我还没有找到一种方法来做到这一点

我试过的

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,这会在一定程度上起作用,但它会以文本形式返回,并且会丢失原始值的格式

那么,长话短说,有没有办法保留原始链接值而不是返回垃圾值呢

另外,我对VBA非常陌生,因此这里可能缺少一些明显的内容。

您可以简单地使用Application.Caller.Text而不是Application.Caller.Value返回单元格的原始文本。这样做的一个缺点是,单元格的值(无论类型如何)将转换为字符串。根据其他单元格/公式,例如,如果您希望其他工作簿返回引用Application.Caller单元格的数字而不是字符串,则可能需要使用=值更新它们

只要您不尝试使用实际单元格中的值更新实际单元格,这将起作用。只要您输入一个单元格,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=CVErrxlErrNull,并按以下方式修改A1公式:=IFERRORUDF。。。;A1


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

为什么不将getValueFromWorkbookOtherWorkbook的结果10复制到当前工作簿中的某个单元格中,然后在此基础上进行计算?这样你就知道一个值永远存在。每次成功调用此UDF时,都将该值更新到本地单元格中。现在,当OtherWorkbook.xlsx不可用时,您可以返回到本地单元格。添加到Jasons建议中,您可以将您的函数包装在iferror语句中,并调用OtherWorkbook函数作为值部分,并使用Jason建议的复制数据作为If错误部分。因此,如果其他工作簿可用,您将从中获取最新的值,如果不可用,您将获取从itApplication.Caller读取的最后一个值。value将始终返回循环引用,因为您正在将单元格传递给自身。您试图向用户显示什么值?我只想在If Err.Number 0 Then语句中放一条消息,说getValueFromWorkbook=Workbook not open,或者其他一些提示,让用户知道工作簿没有打开。不过,我明白你现在在说什么。@PJRosenburg-我会的,但当时我没有时间写一篇合适的文章来回答。我现在要输入一个。从一个单元格调用的函数不能将值写入另一个单元格。@Rory-谢谢。我已经更新了答案,使用GlobalValue变量,而不是将其本地写入单元格。函数现在从这里读取/写入,而不是从实际的单元格中读取/写入。@Rory-您能提供从单元格调用的函数的源代码的任何引用吗?无法将值写入另一个单元格。我只是想写一个UDF函数来生成一个随机数,并使其不可变。我想了解更多您提到的限制。@CBRF23例如,这篇MSKB文章: