VBA UDF 在每次更改后进行评估
Posted
技术标签:
【中文标题】VBA UDF 在每次更改后进行评估【英文标题】:VBA UDF evaluates after every change 【发布时间】:2021-10-26 14:04:57 【问题描述】:我有一个问题,我认为这是一个非常简单的问题,但现在无法处理,所以我猜是错的。 我有一个计算两个日期之间平均汇率的 UDF
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
整个工作簿(调用函数的工作表除外)中的任何更改都会将该函数重新评估为 #VALUE!。我尝试将 UDF 参数化以将这些日期作为输入参数,并激活工作表。我没有其他想法如何处理这个问题。你能帮帮我吗?
【问题讨论】:
range(myRange))
- 这隐含地对ActiveSheet
起作用。试试sh.Range(myRange)
。
【参考方案1】:
由于这些行,当在 [A:A]
列中找不到任何 dateStart
或 dateEnd
时,该函数将返回 #VALUE!
:
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
返回Nothing
并且这些行仍在尝试返回Offset
)
解决方案:首先找到包含Dates
的Cell
,如果找到日期,设置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
【讨论】:
嗯,我通过了那个代码,在我运行任何其他子之前工作正常。当我这样做时,我得到了 2 个 MsgBox,所以日期超出了范围,这很奇怪,因为它们在范围内,为了再次修复它,我需要重新调用该函数。我删除了 volatile 指令,但没有太大变化。 你原来的问题解决了,UDF没有返回#VALUE!不再,这是这个问题的范围。您的新问题似乎与UDF
无关,而是与日期的更新方式、调试函数并找出生成消息时的实际值有关。建议在其他潜艇的开头添加Application.Calculation=xlCalculationManual
,在末尾添加Application.Calculation=xlCalculationAutomatic
,这样UDF
在其他潜艇结束之前不会触发。以上是关于VBA UDF 在每次更改后进行评估的主要内容,如果未能解决你的问题,请参考以下文章