【问题标题】:excel vba preserve original value if UDF formula fails如果 UDF 公式失败,excel vba 保留原始值
【发布时间】:2014-12-11 19:46:46
【问题描述】:

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

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

【问题讨论】:

  • 为什么不直接将getValueFromWorkbook("OtherWorkbook", 10) 的结果复制到当前工作簿的某个单元格中,然后以此为基础进行计算?这样你就知道价值永远存在。每次成功调用此 UDF 时,将值更新到“本地”单元格中。现在当OtherWorkbook.xlsx 不可用时,您可以回退到本地单元格。
  • 添加到 Jasons 的建议中,您可以将函数包装在 iferror 语句中,并将 otherworkbook 函数作为“值”部分调用,并将复制的数据(如 Jason 所建议)用作“If error “ 部分。因此,如果其他工作簿可用,您将获得最新的值,但如果没有,您将获得从中读取的最后一个值
  • Application.Caller.Value 将始终返回循环引用,因为您将单元格传递给自身。你想向用户展示什么价值?我只需在“If Err.Number 0 Then”语句中添加一条消息,说明 getValueFromWorkbook = "Workbook not open" 或其他提示,让用户知道工作簿未打开。
  • 没关系,我明白你现在在说什么了。
  • @PJRosenburg - 我会的,但我没有时间(当时)为答案做一个“适当的”写作。我现在就打一个。

标签: vba excel excel-formula


【解决方案1】:

您可以简单地使用Application.Caller.Text 而不是Application.Caller.Value 来返回单元格的原始文本。这样做的一个缺点是单元格的值,无论 type 是什么,都将被转换为字符串。根据引用 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

【讨论】:

    【解决方案2】:

    这样的事情怎么样:

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

    【讨论】:

    • 从一个单元格调用的函数不能将值写入另一个单元格。
    • @Rory - 谢谢。我已经更新了答案以使用 GlobalValue 变量,而不是在本地将其写入单元格。该函数现在从这里读取/写入,而不是实际的单元格。
    • @Rory - 您能否提供有关此“从单元格调用的函数无法将值写入另一个单元格”的源代码的任何参考。我只是想写一个 UDF 函数来生成一个随机数,并使它不可变,并且很想阅读更多关于你提到的限制。
    • @CBRF23 例如这篇 MSKB 文章:support.microsoft.com/en-us/kb/170787
    【解决方案3】:

    我已经找到了一种方法:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-01
      • 2019-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多