如何实现动态数据验证,例如作为 Excel VBA 函数?

Posted

技术标签:

【中文标题】如何实现动态数据验证,例如作为 Excel VBA 函数?【英文标题】:How do implement dynamic data validation e.g. as Excel VBA-function? 【发布时间】:2019-04-01 17:05:36 【问题描述】:

Excel 中的数据验证是在 Excel 中验证用户输入的有用方法。标准方法是 (1) 在某处(例如在辅助表上)定义一个包含可能输入值的列表,然后 (2) 然后在 Source 字段中选择该范围。或者,也可以直接在该字段中输入不同的选项,例如:

我的问题:我们如何使数据验证列表动态化?

到目前为止,我尝试的是在数据验证对话框的 Source 字段中输入一个返回字符串列表的(可能是用户定义的 VBA)公式,例如

=INDEX("New","Mint","Very Good","Good","Acceptable","Poor",1,RANDBETWEEN(1,6))

但是,这种方法不起作用,因为它会导致错误消息

您不得使用引用运算符(例如联合、交集、 和范围)或数据验证条件的数组常量。

我错过了什么?您建议使用哪种(可能更优雅)使数据验证动态的Source 方式?

编辑:我的具体问题:

在所有(除了第一个)选项卡表上,我有一个名为 myTest 的单元格,允许值列表用于第一个选项卡上的单元格,我希望能够从由所有可能值组成的列表中myTest.

参考资料:

Debra Dalgleish:“创建从属下拉列表”contextures.com Dynamic Data Validation in Excel (Non-VBA!)

【问题讨论】:

我用一堆隐藏的列做过一次。隐藏列的公式根据该行中的某些条目给出不同的值。然后这些值可用于同一行中其他单元格中的数据验证。 当您说“使其动态化”时,您是说源将更改完整位置,还是您希望动态找到源工作表的最后一行并将数据包含在其中?本质上,您提供有关一般概念的信息,而没有为您的特定情况下需要什么和需要什么提供任何基础,这将导致一个固执己见或开放式的讨论,而不是一个可回答的问题,这个论坛需要。 @Cyril 的评论很中肯:您到底是想要做什么,还是只是在探索?如果您使用 VBA 函数作为验证列表的源,它必须在工作表上返回一个范围,并且该范围必须是连续的。 @horst:您的方法不适用于我的情况,因为允许值范围的长度可能会有所不同。 我相信您可以粘贴到 DV 对话框中的逗号分隔列表的长度是有限制的 - 超过这个长度,您需要将其指向一个范围。 【参考方案1】:

您可以在第一张工作表的代码模块中使用类似的内容:

Private Sub Worksheet_Activate()

    Const LIST_COL As Long = 26
    Dim sht As Worksheet, i As Long

    i = 1
    Me.Columns(LIST_COL).ClearContents       '<< clear current list
    For Each sht In ThisWorkbook.Worksheets  '<< collect all the values
        If sht.Name <> Me.Name Then            
            Me.Cells(i, LIST_COL).Value = sht.Range("myTest").Value
            i = i + 1
        End If
    Next sht

End Sub

它会将其他工作表中的值收集到您可以参考的验证列表范围内。

注意:如果其他工作表的值是通过代码或公式更新的(即,不需要您转到每个工作表来更改值),那么您需要做更多的工作。


编辑 - 这更复杂,但工作更可靠,因为只要您点击验证下拉菜单,它就会运行

1. 将其放入常规模块中(根据需要进行编辑):

'A function to return a range containing the 
'  various values which need to appear in the validation list
Public Function ListCompile() As Range

    Const LIST_COL As Long = 26      '<< create the list in Col Z
    Dim sht As Worksheet, i As Long

    i = 1
    Sheet1.Columns(LIST_COL).ClearContents
    For Each sht In ThisWorkbook.Worksheets
        If sht.Name <> Sheet1.Name Then
            Sheet1.Cells(i, LIST_COL).Value = sht.Range("myTest").Value
            i = i + 1
        End If
    Next sht
    'return the list we just created
    Set ListCompile = Sheet1.Cells(1, LIST_COL).Resize(i, 1)
End Function

注意:我使用的是 Sheet1 的代号(可能与选项卡名称不同)。您可以在 VB 编辑器 Project Explorer 中看到代码名称。

2.定义一个命名范围“tester”,其中“RefersTo”等于ListCompile()

3. 最后将你的数据验证列表范围设置为:=tester

【讨论】:

所有工作表上的myTest 的值实际上可以更改,因此每次用户单击下拉菜单时更新允许值列表确实是有意义的。【参考方案2】:

假设:

您的列表在 A 列中 没有标题

您可以使用此公式作为来源,使用动态列表进行数据验证:

=OFFSET(A1,0,0,COUNTA(A:A),1)

编辑: 下面是在数据验证中使用上述公式应用于单元格 B1 的示例图像:

如果您能以某种方式将您的值合并到一个列中,这是一种可能。

【讨论】:

你的代码到底是做什么的?我相信我们可能误解了彼此 - 我正在寻找某种技巧,它可以在大约 5 到 20 个不同的选项卡(每个都有这个 myTest)上累积所有名为 myTest 的单元格的值。

以上是关于如何实现动态数据验证,例如作为 Excel VBA 函数?的主要内容,如果未能解决你的问题,请参考以下文章

我可以使用 VBA 函数将可接受值的(动态)列表返回到 Excel 的数据验证中吗?

带高亮显示的动态搜索 - Excel VBA

Excel VBA:将计算结果数组作为参数传递给函数

在excel中如何用vba来实现查找特定的字符串?

Excel 请问如何破解VBA工程不可查看

识别不同的动态数组 VBA Excel