在 UDF 中使用命名范围
Posted
技术标签:
【中文标题】在 UDF 中使用命名范围【英文标题】:Use Named Range in UDF 【发布时间】:2016-05-10 15:04:55 【问题描述】:我正在尝试创建一个使用命名范围的 UDF。我的命名范围(“best_Grade”)是一个带有值的单元格。 (命名范围的范围是工作簿)。
在工作簿模块中,当我尝试使用命名范围创建变量时,我得到 p>
运行时错误“1004”:对象“_Global”的“范围”方法失败
这两行都不行:
Dim namedRng As Range
Dim locDataWS As Worksheet
Set locDataWS = Sheets("Approval matrix 16")
Set namedRng = Range("best_Grade") ' errors
Set namedRng = locDataWS.Range("best_Grade") ' When I take above line out, this line errors too
我试过了:
Dim wb As Workbook
Set wb = ActiveWorkbook
Set namedRng = wb.Names("best_Grade").RefersToRange
怎么会出错? This page 说它应该可以工作,不是吗?我是否必须将此 UDF 放在实际的工作表对象上,而不是放在工作簿模块中?
编辑:注意:命名范围不是设置为单元格,而是 SumIf 公式 (best_Grade = SumIf(A2:A10,"x",...)` 可能导致错误?
Edit2:是的,这就是我认为的原因。我为随机单元格创建了一个命名范围,并且能够使用 Range("a_grade").Value
并返回预期值。由于我的best_Grade
范围是一个公式,我认为这就是它出错的原因。但是,我不知道为什么,因为我认为命名范围就是命名范围,无论它是由什么组成的......
编辑 n+1:注意这里有两个“答案”。如果我想继续使用命名范围作为 Range
变量,请参阅下面的答案。然而,我真正想做的是@MacroMarc 发布的内容,所以我选择了它作为“答案”。
【问题讨论】:
根据我的经验,引用命名范围与地址不同,因为您必须首先使用对工作表的引用来限定它。也就是说,我原以为你说的第二行错误应该只要删除前一行就可以工作。 @MacroMan - 我想我偶然发现了为什么它会返回这样的错误。由于命名范围未设置为单元格,而是设置为公式,因此会出错。我想我要做的就是有一个辅助单元格,给 that 一个命名范围,然后使用它。但是,如果可能的话,我想使用我的公式命名范围... @findwindow 不用担心,反正还没有人接受我! @BruceWayne 是的,这就是问题所在。您是否尝试过改用Application.Evaluate()
?
@Findwindow 我看到 Scott 不再是你的导师了,否则你会尝试为 sumproduct 或聚合函数定义一个名称! 8)
【参考方案1】:
您需要改用 Names 集合:
Sub t5()
' named range "Test" is `=Sum($A$1:$A$4)`
Dim rng As Double
rng = Evaluate(Names("Test").Value)
Debug.Print rng
End Sub
Name 对象必须返回字符串表示形式的各种属性。
【讨论】:
你不可能像我开始回答之前那样快两秒钟回答!你的 ESP 坏了吗……别等了,不是,你是故意的!我更喜欢你的回答,因为它摆脱了那些额外的应用程序和工作簿参考。 (我编辑并关闭了最后一个括号)。感谢您和您的 cmets!【参考方案2】:Sub t5()
' named range "Test" is `=Sum($A$1:$A$4)`
Set wb = ActiveWorkbook
Dim rng As String
rng = wb.Names("Test").RefersTo
Debug.Print rng
rng = Application.Evaluate(wb.Names("Test").RefersTo)
Debug.Print rng
End Sub
经过一些测试,我发现上面的方法很有效……而且很有趣。我在 Chip Pearson 帖子中也从 Macro Man 的评论中获得了领先。
关键是定义的名称返回一个字符串 =“你的结果”,所以你可以评估它来获得答案,或者你可以做一些字符串操作来去掉引号和等号。你真的很接近你的 RefersToRange 选择。
在您自己发布的答案下查看 Vegard 的评论。
【讨论】:
是的!这就是诀窍,感谢您通过它并找到它。干杯! (现在如果你或@MacroMarc 应该被标记为答案,我很伤心!) 我无法帮助您做出这个决定。好吧,也许我可以。宏是第一位的,需要更多的代表点,我认为 VBA 是他的领域而不是我的领域。我仍在学习 VBA 语法和注意事项。它们的答案略有不同。我认为他的 VBA 语法看起来更简洁/不那么冗长。 我也是这么想的——把它给了他,但真的非常感谢你的帮助!干杯!【参考方案3】:它不起作用的原因是因为我的命名范围best_Grades
不是单元格引用,而是一个公式。因此,当使用Range("best_Grades").Value
时,它会出错。 (best_Grades = SumIf(A2:A10,"x", B2:B10, ...)
不知道为什么,因为我认为命名范围是命名范围,不管它是由什么组成的......但我想不是。
目前,我的解决方案只是根据实际的单元格值创建另一个命名范围,然后使用它。 (theBest_Grades = A2
)。然后,我可以直接拨打Range("theBest_Grades").Value
没有任何问题。
我将把它打开几天,以防有人知道如何将我的公式命名为范围,并在 VBA 中使用它。
编辑:这基本上是我最初拥有工作表/命名范围的方式:
命名范围为:
但是,正如我所说,您不能在 VBA 中使用那种类型的命名范围(至少我没有找到)。
所以,为了解决这个问题,我只是在单元格中使用了 SumIf,并为该单元格指定了命名范围:
现在我可以毫无问题地使用Range("findWindow_Example").Value
。
编辑 n+1:
我试着用Double
做一个简单的测试,但同样的事情,它出错了:
Sub t5()
' named range "Test" is `=Sum($A$1:$A$4)`
Dim rng As Double
rng = Range("Test") 'Run time error 1004
Debug.Print rng
End Sub
【讨论】:
我要说的是一个包含单元格范围的命名范围保存单元格地址值。因此,您声明范围的变量可以处理单元格地址。当您的命名范围是公式时,它会返回结果或值。试图使您声明的范围等于字符串或某个数字的变量是不行的。因此,如果您将变量定义为 DOUBLE,那么它可能会采用您的命名范围吐出的值......并且记得按照我的想法删除设置部分。 lol dat 变量名 ^_^ 编辑:哦,伙计,你不能做脸红表情,因为*
是保留 XD
@ForwardEd - 查看我的编辑,我想我尝试了你提到的。它也不起作用,除非我误读了你的评论。
看看this explanation的底端。我认为是最后三个。
@BruceWayne:如果还没有指定,ForwardEd 想说的是,您指定的命名范围不返回范围对象(它返回一个字符串格式公式),这也是为什么你不能做 Set rng = Names("test")
以及为什么使用 Evaluate
的答案有效。【参考方案4】:
我没有看到这里提到的一件事是 UDF 的基本规则在这里被打破了恕我直言:
UDF 需要的所有信息都应通过其参数传递给 UDF。
如果您遵守该规则,使用任何范围名称都会变得简单,因为范围名称的值会自动传递给参数。
【讨论】:
感谢您的评论 - 到目前为止,我只真正使用 UDF 进行快速测试/检查。我一定会记住这一点,因为我会让它们更健壮/做其他事情。【参考方案5】:不止一位回答者找到了解决问题的正确方法,但正如我在 cmets 中所说的(随后,其他人可能对此想法感兴趣),尚未指定错误的原因。
您定义的命名范围不返回范围对象。这意味着这段代码:
Dim namedRng As Range
Set namedRng = Range("best_Grade")
不可能工作(主要是因为命名范围返回一个数值。如果它返回一个字符串地址表示,它可能已经通过一些语法改进工作)。
为了从编译器的角度说明这一点,请查看此处立即窗口中的打印输出(尤其是第一行):
如果我们假设初始代码是伪代码,那么编译器所要求的就是从公式中构造一个范围(也不是它的结果!)。
因此,如果我们将Set namedRng = Range("best_Grade")
替换为Set namedRng = Range(Names("namedRange"))
,结果可能(但不一定——见帖子结尾!)如下所示:
Set rng = Range("=SUMIF('Ark1'!$B$1:$B$5, "x", 'Ark1'!$A$1:$A$5)")
当然,这是行不通的。但是,正如其他答案所表明的那样,将namedRange
放入Evaluate
是完全合法的!
有趣的是,如果我们执行 ? Evaluate(Names("namedRange"))
(省略 .Value),我们会得到一个错误 2015,尽管我们能够询问编译器 ? Names("namedRange")
并得到一个字符串作为回报!
【讨论】:
以上是关于在 UDF 中使用命名范围的主要内容,如果未能解决你的问题,请参考以下文章
在 ColdFusion UDF 中,有没有办法从父函数范围引用变量?