VBA UDF 在每次更改后计算

VBA UDF evaluates after every change

我有一个问题,我认为会是一个非常简单的问题,但现在无法处理,所以我猜错了。 我有一个 UDF 可以计算 2 个日期之间的平均汇率

Option Explicit
Public Function averageFromRange() As Double

Dim sh As Worksheet
Set sh = ThisWorkbook.Worksheets("Exchange Rates")

Dim dateStart As Date: dateStart = sh.range("G1").Value
Dim dateEnd As Date: dateEnd = sh.range("G2").Value

Dim myRange As String
Dim rangeStart As range
Dim rangeEnd As range

Set rangeStart = sh.range("A:A").Find(What:=CStr(dateStart), LookAt:=xlWhole, LookIn:=xlValues).Offset(0, 1)
Set rangeEnd = sh.range("A:A").Find(What:=CStr(dateEnd), LookAt:=xlWhole, LookIn:=xlValues).Offset(0, 1)

If rangeStart Is Nothing Then
    MsgBox ("Date " & dateStart & " out of range")
End If

If rangeEnd Is Nothing Then
    MsgBox ("Date " & dateEnd & " out of range")
End If

If Not (rangeStart Is Nothing Or rangeEnd Is Nothing) Then
    myRange = rangeStart.Address & ":" & rangeEnd.Address
    averageFromRange = Application.WorksheetFunction.Average(range(myRange))
End If
End Function

整个工作簿中的任何更改(调用函数的 sheet 除外)都会将函数重新计算为 #VALUE!。我尝试对 UDF 进行参数化以将这些日期作为输入参数,并激活 sheet。我没有其他想法如何处理这个问题。你能帮帮我吗?

函数 returns #VALUE!dateStartdateEnd 由于这些行而在列 [A:A] 中找不到时:

Set rangeStart = sh.range("A:A").Find(What:=CStr(dateStart), LookAt:=xlWhole, LookIn:=xlValues).Offset(0, 1)
Set rangeEnd = sh.range("A:A").Find(What:=CStr(dateEnd), LookAt:=xlWhole, LookIn:=xlValues).Offset(0, 1)

这些行试图设置 Nothing Offset(0, 1)(即 Find returns Nothing 并且这些行是仍在尝试 return Offset)

解决方法: 首先找到包含 DatesCell 然后如果找到日期,设置 Offset 范围。

如果列 [A:A]Dates(开始和结束)由公式更新,您可能还希望 UDF 为 Volatile

试试这个代码:

Public Function averageFromRange() As Double

Dim dDateIni As Date, dDateEnd As Date
Dim rINI As Range, rEND As Range

    Application.Volatile    'Comment this line is VOLATILE is not required
    With ThisWorkbook.Worksheets("Exchange Rates")
    
        dDateIni = .Range("G1").Value
        dDateEnd = .Range("G2").Value
    
        With .Columns(1)
            Set rINI = .Find(What:=CStr(dDateIni), LookAt:=xlWhole, LookIn:=xlValues)
            Set rEND = .Find(What:=CStr(dDateEnd), LookAt:=xlWhole, LookIn:=xlValues)
        End With
    
    End With
            
    If rINI Is Nothing Then MsgBox ("Date " & dDateIni & " out of range")
    If rEND Is Nothing Then MsgBox ("Date " & dDateEnd & " out of range")
    If Not (rINI Is Nothing And rEND Is Nothing) Then
        averageFromRange = Application.Average(Range(rINI.Offset(0, 1), rEND.Offset(0, 1)))
    End If
        
    End Function

使用的资源: Worksheet.Range, With statement