Vba 数据验证和工作表更改事件

Vba 数据验证和工作表更改事件,vba,excel,Vba,Excel,当使用工作簿激活事件打开工作簿时,我使用VBA宏查询数据库并生成可用项目的列表。我有项目编号和项目名称,它们组合成两个单独的数据验证列表,并应用于两个单元格。工作表更改事件测试这些单元格中的更改,将其数据验证列表拆分为数组,并从另一个数组中选择相应的项目信息。例如,如果我选择了一个项目编号,工作表更改事件将在项目编号数组中查找项目编号的位置,然后根据位置从名称数组中选择项目名称 无论何时从下拉列表中选择一个值,这都非常有效,但当输入列表之外的值时,我会遇到问题。例如,如果输入一个空白单元格,则可

当使用工作簿激活事件打开工作簿时,我使用VBA宏查询数据库并生成可用项目的列表。我有项目编号和项目名称,它们组合成两个单独的数据验证列表,并应用于两个单元格。工作表更改事件测试这些单元格中的更改,将其数据验证列表拆分为数组,并从另一个数组中选择相应的项目信息。例如,如果我选择了一个项目编号,工作表更改事件将在项目编号数组中查找项目编号的位置,然后根据位置从名称数组中选择项目名称

无论何时从下拉列表中选择一个值,这都非常有效,但当输入列表之外的值时,我会遇到问题。例如,如果输入一个空白单元格,则可能会出现数据验证错误,或者在使用match查找数组中输入的值时,可能会出现类型不匹配。我有一个错误处理程序来处理类型不匹配,但我希望每次都触发数据验证错误。另一个问题是事件有时会被禁用。这更为严重,因为用户将无法重新打开这些功能

最重要的是,我不知道这是在哪里发生的,或者是如何发生的。我无法复制使用中断来禁用事件的方式,因为复制导致在中断处于适当位置时禁用事件的步骤只会导致错误处理程序。但是,当未应用中断时,错误处理程序有时将无法触发,事件将被禁用。因为我在解析数组之前禁用了事件,所以我认为工作表更改在
Loc=Application.Match(Target.Text,NumArr,0)-1
行失败,但我不明白为什么不会触发错误。至少,我应该得到一条带有错误号和描述的消息,并且应该重新启用事件

有人能就工作表更改和数据验证之间的相互作用提出建议吗?这里的通话顺序是什么?还有其他建议吗?我遗漏了什么

埃塔:我已经在谷歌上搜索过了,但是我没有找到任何有用的东西。出现的一切都是关于将数据验证转化为工作表更改,而与交互或调用顺序无关

ETA#2:在尝试了下面答案中的实验后(感谢Gary的学生),这变得有点奇怪。如果我选择“重试”并选择旧的默认值,我会得到三次旧值。如果我点击delete,我会在消息框中得到一个空格,但只有一个消息框。然后将单元格留空。我可以通过单击“重试”并接受空格将DV放入循环中。DV错误将出现,直到我单击“取消”。然后我将得到一系列空的文本消息框,每次我重试空单元格时都会有一个。如果我从列出的值开始,用backspace清除单元格,单击“重试”,然后尝试选择另一个值,则工作表更改事件会失败3次。我认为下面的答案更清楚地说明了正在发生的事情,但也提出了更多的问题

以下是我的代码:

Private Sub Worksheet_Change(ByVal Target As Range)

Dim NumArr() As String
Dim ProjArr() As String
Dim Loc As Integer

On Error GoTo ErrHandler:

If Target.Address = "$E$4" Then
    'Disable events to prevent worksheet change trigger on cell upates
    Application.EnableEvents = False

    'Parse validation lists to arrays
    NumArr = Split(Target.Validation.Formula1, ",")
    ProjArr = Split(Target.Offset(1, 0).Validation.Formula1, ",")

    'Change error handler
    On Error GoTo SpaceHandler:

    'Determine project number location in array
    Loc = Application.Match(Target.Text, NumArr, 0) - 1

    'Change error handler
    On Error GoTo ErrHandler:

    'Change cell value to corresponding project name based on array location
    Target.Offset(1, 0) = ProjArr(Loc)

    'Unlock cells to prepare for editing, reset any previously imported codes
    Range("C8:G32").Locked = False

    'Run revenue code import
    RevenueCodeCollector.ImportRevenueCodes

    'Re-enable events
    Application.EnableEvents = True

End If

If Target.Address = "$E$5" Then

    Application.EnableEvents = False

    NumArr = Split(Target.Validation.Formula1, ",")
    ProjArr = Split(Target.Offset(-1, 0).Validation.Formula1, ",")
    Loc = Application.Match(Target.Text, NumArr, 0) - 1
    Target.Offset(-1, 0) = ProjArr(Loc)

    Range("C8:G32").Locked = False
    RevenueCodeCollector.ImportRevenueCodes
    Application.EnableEvents = True

End If

Exit Sub

ErrHandler:
MsgBox Err.Number & " " & Err.Description
Application.EnableEvents = True
Exit Sub

SpaceHandler:
MsgBox "Pick a project from the dropdown.", vbOKOnly, "Error"
Application.EnableEvents = True

End Sub

你有一个非常开放的问题…………没有时间做一份完整的白皮书,这里有一个简单的实验。我使用事件代码:

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim A1 As Range, rINT As Range

    Set A1 = Range("A1")
    Set rINT = Intersect(A1, Target)
    If rINT Is Nothing Then Exit Sub
    MsgBox A1.Value
End Sub
A1中,我设置DV如下:

如果我使用下拉列表,我会得到输入的值,同时也会得到
MsgBox
。但是,如果我单击单元格并键入一些垃圾,会发生以下情况:

  • DV警报出现,我按下取消按钮
  • 我得到了2次
    MsgBox
    事件,每次都是原始内容,而不是尝试的垃圾 我完全不知道为什么会引发事件,因为单元格没有实际更改,更不用说为什么会引发两次事件了!!就好像 该事件在垃圾条目上引发,但DV报警具有优先级,DV反转条目并引发另一个事件,最后两个事件都得到处理


    希望有一个比我更聪明的人会加入进来。

    参考查询,DV和更改事件的解决方案得到管理

    Public strRange As String
    Public bCheck As Boolean
    
    Private Sub Worksheet_Change(ByVal Target As Range)
    If bCheck Then Exit Sub
    
    MsgBox "Correct Entry!"
    
    strRange = Target.Address
    bCheck = True
    End Sub
    
    Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    If Target.Address <> strRange Then bCheck = False
    End Sub
    
    publicstrrange作为字符串
    公共bCheck为布尔型
    私有子工作表_更改(ByVal目标作为范围)
    如果选择B,则退出Sub
    MsgBox“正确输入!”
    strRange=Target.Address
    b检查=True
    端接头
    专用子工作表\u选择更改(ByVal目标作为范围)
    如果Target.Address strRange,则bCheck=False
    端接头
    

    很抱歉,如果您把它放在那里,但是如果没有错误处理程序,哪一行会发生什么错误?嗯,就是这样。我找不到发生错误的地方。如果我输入DV revejcts的垃圾数据,“Loc=Application.Match…”行将由于类型不匹配而失败,这是给定的。然而,这之后所有事情的处理方式给我带来了麻烦。请看我的编辑…很抱歉问题的开放性。我想不出具体要问什么,因为我不知道发生了什么。不过,这个实验确实澄清了很多问题。我想知道其中一个事件的失败是否不是导致事件被禁用的原因,并且这两个事件的处理以某种方式掩盖了失败。我认为对Excel有更深入了解的人必须回答这个问题。再次感谢!