我可以使用VBA函数将可接受值的(dynamic)列表返回到Excel的数据validation中吗?
对于给定的单元格,我selectData / Validation并将Allow设置为“List”。 我现在希望像这样设置Source:
= rNames(REGS)
但不起作用(名称未find)。 所以我去插入/名称/定义和创build“REGNAMES”通过简单地分配上面的公式(没有细胞范围)。 然后我回到数据/validation,当我设置源如此:
= REGNAMES
现在我得到“源目前评估错误”。 不幸的是,即使我忽略了这个错误也不会消失。 我可以在工作表中创build一个范围公式,如下所示:
{= REGNAMES}
并通过一对单元格将其拖到右侧,并且rNames函数会忠实地返回
选项#1 | 选项#2 | …
也就是说,该函数按预期返回一个范围。
我知道我可以使用macros代码来处理VBA中该单元格的List设置。 我不喜欢这些副作用。 我宁愿build立在函数上的干净的依赖关系树。 任何想法如何获得数据/validation接受从rNames返回的数组值?
谢谢。
PS:rNames返回结果范围作为Variant,如果有任何方位。
我认为问题是数据validation对话框只接受以下“列表”:
-
直接inputSource字段的实际列表
-
字面范围参考(如$ Q $ 42:$ Q $ 50)
-
一个命名的公式本身parsing为一个范围引用
最后一个是关键 – 没有办法让VBA函数返回一个可用于validation的数组,即使你从一个命名的公式调用它。
你可以编写一个返回范围引用的VBA函数,然后从一个命名的公式中调用它 。 这可以作为以下技术的一部分,它可以近似实现您实际需要的function。
首先,有一个实际的范围调用你的任意数组返回的VBA UDF。 说你有这个function:
Public Function validationList(someArg, someOtherArg) 'Pretend this got calculated somehow based on the above args... validationList = Array("a", "b", "c") End Function
你从$ Q $ 42:$ Q $ 50作为一个数组公式来调用它。 你会得到三个“a”,“b”和“c”的单元格,其余的单元格会有#N / A错误,因为返回的数组小于调用UDF的范围。 到现在为止还挺好。
现在,让另一个VBA UDF返回一个范围的“占用”部分,忽略#N / A错误单元格:
Public Function extractSeq(rng As Range) 'On Error GoTo EH stuff omitted... 'Also omitting validation - is range only one row or column, etc. Dim posLast As Long For posLast = rng.Count To 1 Step -1 If Not IsError(rng(posLast)) Then Exit For End If If rng(posLast) <> CVErr(xlErrNA) Then Exit For End If Next posLast If posLast < 1 Then extractSeq = CVErr(xlErrRef) Else Set extractSeq = Range(rng(1), rng(posLast)) End If End Function
然后你可以从一个命名的公式调用它,如下所示:
=extractSeq($Q$42:$Q$50)
并且指定的公式将返回Excel将接受允许的validation列表的范围引用。 笨重,但副作用免费!
请注意在上面的代码中使用关键字“设置”。 从你的问题中不清楚,但是这可能是整个答案的唯一部分对你很重要。 如果在尝试返回范围引用时不使用“设置”,则VBA将返回范围的值 ,该值不能用作validation列表。
我只是做了一些关于访问Shapes下拉控件的内容的研究,并发现了另一种解决这个问题的方法,你可能会觉得有帮助。
任何可以应用validation规则的范围都可以通过编程应用该规则。 因此,如果要将规则应用于单元格A1,可以这样做:
ActiveSheet.Range("A1").Validation.Add xlValidateList, , , "use, this, list"
上面添加了包含项目“use”,“this”和“list”的单元格内下拉validation。 如果覆盖Worksheet_SelectionChange()
事件并检查其中的特定范围,则可以调用任意数量的例程来创build/删除validation规则。 这种方法的优点是所引用的列表可以是可以在VBA中创build的任何列表。 我需要一个dynamic生成的工作簿中不断变化的工作表子集的列表,然后将它们连接在一起以创buildvalidation列表。
在Worksheet_SelectionChange()
事件中,我检查范围,然后如果匹配,则触发validation规则子,从而:
Private Sub Worksheet_SelectionChange(ByVal Target as Range) If Target.Address = "$A$1" Then UpdateValidation End If End Sub
UpdateValidation()
中的validation列表生成器代码执行以下操作:
Public Sub UpdateValidation() Dim sList as String Dim oSheet as Worksheet For Each oSheet in Worksheets sList = sList & oSheet.Name & "," Next sList = left(sList, len(sList) -1) ' Trim off the trailing comma ActiveSheet.Range("A1").Validation.Delete ActiveSheet.Range("A1").Validation.Add xlValidateList, , , sList End Sub
而现在,当用户点击下拉箭头时,他/她将被呈现更新的validation列表。
听起来像你的rNames函数可能会返回一维数组(这将被视为一个行)。
尝试让你的函数返回一个列作为基于1的二维数组(Ansa(1,1),然后Ansa(2,1)等)
你不是使用dynamic范围名称吗? 这很容易,不需要任何vba。
为将来:
然后在命名范围内使用以下命名范围,并将命名范围设置为“数据validation”“列表”值
Function uniqueList(R_NonUnique As Range) As Variant Dim R_TempList As Range Dim V_Iterator As Variant Dim C_UniqueItems As New Collection On Error Resume Next For Each V_Iterator In R_NonUnique C_UniqueItems.Add "'" & V_Iterator.Parent.Name & "'!" & V_Iterator.Address, CStr(V_Iterator.Value2) Next V_Iterator On Error GoTo 0 For Each V_Iterator In C_UniqueItems If R_TempList Is Nothing Then Set R_TempList = Range(V_Iterator) End If Set R_TempList = Union(R_TempList, Range(V_Iterator)) Next V_Iterator Set uniqueList = R_TempList End Function