在 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 中,有没有办法从父函数范围引用变量?

模式匹配范围在Scala与Spark udf

在 SQL 中编写函数以遍历 UDF 中的日期范围

在 UDF 中设置时,在需要 range.cell 的范围内选择一个单元格

Excel UDF 对变量工作表的范围求和