使用 Evaluate 写入其他单元格的 UDF 是不可预测的
Posted
技术标签:
【中文标题】使用 Evaluate 写入其他单元格的 UDF 是不可预测的【英文标题】:UDF using Evaluate to write to additional cells is unpredictable 【发布时间】:2017-04-24 23:34:28 【问题描述】:我不愿意询问有关 UDF 被设计为写入其他单元格的问题,因为按照设计,这种行为应该被禁用。但是...我将克服所有潜在的批评并提出要求。我真的不希望完全回答这个问题,所以我只是想了解一下我遇到的奇怪行为。
我有一个用于计算简单轴承允许值的 UDF。它需要 10 个参数。如果任何参数超出范围,UDF 将在调用单元格中返回“错误”。我想通过列出所有有问题的输入来整合这个相当无用的反馈,这样用户就不必一个接一个地进行单个更正。这样,所有错误的输入都会被列出,用户可以一次更正所有的输入。仅供参考,由于某些输入交互,输入存在 10 多个潜在问题。否则,用户可能会尝试按摩输入数十次而没有成功。这就是我想一次列出所有反馈的原因。
UDF:速记 - 它将数据发送到类模块以执行所有检查和计算。
public Function LBA(ByVal layup_string As String, ByVal diaBolt As Double, ByVal boltHead As String, _
ByVal eD As Double, ByVal tMetallicFitting As Double, ByVal tempF As Double, ByVal depth As Double, _
ByVal allowable_type As String, ByVal basis As String, ByVal cond As String) As Variant
'
' declare variables
Dim s As String
Dim val As Variant
Dim clba As New cFunc_LBA
'
' send to class constructor
clba.init layup_string, diaBolt, boltHead, eD, tMetallicFitting, tempF, depth, allowable_type, basis, cond
'
' get errors
If clba.contains_errs Then ' ............................... check for design space violattions: errors
s = clba.get_errs ' .................................... get concat string of all errors
Evaluate ("post_error_messages(""" & s & """)") ' ...... run the subroutine to post err msgs
val = "Error" ' ........................................ return value to calling cell
'
Else
'
' return a valid bearing allowable
val = clba.LBA ' ....................................... expose bearing allowable property
'
End If
'
LBA = val
End Function
类模块按预期工作。所有计算和错误日志都有效。在 UDF 中,当我检查是否有错误时,它会返回错误。然后我将错误(在一个长连接字符串中)发送到另一个子程序,该子程序应该将错误输出到其他工作表单元格中。
子:
Private Sub post_error_messages(ByVal s As String)
' declare variables
Dim arr As Variant
'
' initialize variables
arr = Split(s, ",")
'
' post error messages
For i = 0 To UBound(arr) ' .................. loop thru error messages
m.Cells(17 + i, 2) = CStr(arr(i)) ' ..... write msg in cell, increment by ROW#
Next i
End Sub
我在此过程中注意到的一个怪癖......我只能让子例程(由 Evaluate 调用)接受一个参数。我也只能让它接受一个简单的数据类型string
。我试过arrays
、variants
、scripting.dictionary
,但都没有奏效。因此,我所有的错误消息都连接成一个长字符串,然后拆分并在 sub 中循环。
我现在的问题是,这种设置只能起到某种作用。
问题 1:无论返回多少错误,Sub 发布错误消息都只会返回三个项目。事实上,它总是返回三个项目,即使只有两个(显示的最后一个被重复)。如果有 10 条错误消息 - 显示 3 条。我将debug.print
语句放在我的错误消息子中,这样我就可以看到发生了什么,它表明当只返回 2 条错误消息时,它应该只打印到 2 个单元格,但无论如何它都会打印到第三个单元格。超过 3 个错误被丢弃。
问题 2:如果我删除工作表中显示错误消息的单元格并再次执行 UDF,则消息将不会返回。只有当我关闭工作簿并再次打开它时,错误消息子例程才会再次打印到单元格(来自 UDF)。
另外,这并不是一个真正的问题,Evaluate 运行了两次。我已经查过了,这似乎是一个已知问题。我只是把它放在那里,但我不确定这会导致任何问题。
再次,由于我在 Excel 的 UDF 的预期功能之外工作,我不希望有解决方案。也就是说,任何人都可以对此提供任何见解吗?
【问题讨论】:
您没有将 post_error_message 功能放入 Worksheet.Calculate 事件中是否存在技术原因?还是使用对话框显示错误列表?m
在哪里/如何声明和填充?
m
是 udf 所在的工作表。感谢 Tim,这个 UDF Evaluate 方法直接来自您的一篇文章。
@RichHolton 我正在将我的代码添加到其他人的工作簿中。里面有很多东西,我不想把事件混在一起。此外,还有一个将错误发布到工作表单元格的请求。在阅读了蒂姆关于这种方法的帖子后,我想我会尝试一下。
为什么不创建另一个 UDF,比如 LBA_ERROR(lbaCell as Range),它返回与指定单元格中的 LBA 函数关联的错误列表?它可以返回一个多行字符串,或者您可以为错误行号添加一个参数,并拥有一系列包含对 LBA_ERROR() 的调用的单元格。这为查找错误消息提供了灵活性,并符合 Excel 的限制。
【参考方案1】:
不是您问题的答案,但这个精简版对我来说可以:
Public Function LBA() As Variant
Dim val, s
s = "A,B,C,D,E"
Evaluate "post_error_messages(""" & s & """)"
val = "Error" '
LBA = val
End Function
Private Sub post_error_messages(s As String)
Dim arr As Variant, i
With Sheet1.Cells(17, 2)
.Resize(10, 1).Value = "" '<<< clear any previous errors!
arr = Split(s, ",")
.Resize(UBound(arr) + 1, 1).Value = Application.Transpose(arr)
End With
End Sub
【讨论】:
以上是关于使用 Evaluate 写入其他单元格的 UDF 是不可预测的的主要内容,如果未能解决你的问题,请参考以下文章