VBA:忽略For-Each循环中的条件

时间:2017-03-13 22:22:34

标签: excel vba excel-vba

问题陈述

我为这些国家/地区的某些国家和州提供了几个相关的组合框。我使用VBA在第一个组合框中填充唯一值,然后在第二个组合框中动态填充唯一值。代码似乎忽略了初始传递中的条件。

例如,代码适用于第一个国家/地区:

enter image description here

但是以下国家/地区错误地保留了第一个州值:

enter image description here

数据

这是数据集,名称"国家"和"州"。这些名称动态对应于每个标题下方的范围:

enter image description here

名称引用使用以下格式的公式:

=OFFSET(Sheet1!$A$2,0,0,COUNTA(Sheet1!$A:$A),1)

组合框是ActiveX对象,其名称为#34; countries"和"州"分别

代码

代码段:

Private Sub Worksheet_Activate()
'Populate combo box with unique countries.
  Dim arr() As String
  Dim tmp As String
  Dim rng As Range
  Dim ws As Worksheet
  Set ws = Worksheets("Sheet1")
  Me.countries.Clear
  For Each rng In ws.Range("Country")
    If (rng <> "") And (InStr(tmp, rng) = 0) Then
      tmp = tmp & rng & "|"
    End If
  Next rng

  If Len(tmp) > 0 Then tmp = Left(tmp, Len(tmp) - 1)

  arr = Split(tmp, "|")

  Me.countries.List = arr

End Sub

Private Sub countries_lostfocus()
  'Populate dependent combo box with unique states
  'according to selection in countries combo box.
  Dim rng As Range
  Dim ws As Worksheet
  Dim str As String
  Set ws = Worksheets("Sheet1")
  str = countries.Value
  Me.states.Clear
  On Error Resume Next
  For Each rng In ws.Range("State")
    If ((rng.Offset(, -1).Value) = str) And (IsNotInArray(rng.Value, Me.states.List)) Then
      Me.states.AddItem rng.Value
    End If
  Next rng
End Sub

Function IsNotInArray(stringToBeFound As String, arr As Variant) As Boolean
  IsNotInArray = IsError(Application.Match(stringToBeFound, arr, 0))
End Function

新州州的州值将存储在所有后续国家/地区的组合框中。

使用MsgBox在循环内调试:

  For Each rng In ws.Range("State")
    If ((rng.Offset(, -1).Value) = str) And (IsNotInArray(rng.Value, Me.states.List)) Then
      MsgBox ("Country: " & str & "; check: " & rng.Offset(, -1).Value)
      Me.states.AddItem rng.Value
    End If
  Next rng

似乎表明,在选择澳大利亚以外的国家时,条件的第一部分无法按预期运作:

enter image description here

2 个答案:

答案 0 :(得分:2)

尽管我不希望新南威尔士州被排除在任何列表之外,但您可以通过在尝试执行arr之前测试Match变量是否为空来解决您的问题:

Function IsNotInArray(stringToBeFound As String, arr As Variant) As Boolean
    If UBound(Arr) = -1 Then
        IsNotInArray = True
    Else
        IsNotInArray = IsError(Application.Match(stringToBeFound, arr, 0))
    End If
End Function

如果将arr作为ComboBox的清除列表传递给该函数,则其LBound为0且UBound为-1,因此对{的测试{1}}会阻止UBound崩溃。

答案 1 :(得分:1)

您可以使用与Country相同的方法。为什么不使用countries_Change事件?

Option Explicit

Private Sub countries_Change()
    Dim sCountry As String
    Dim sList As String
    Dim rng As Range
    sCountry = Me.countries.Value
    Me.states.Clear
    With ThisWorkbook.Names("State")
        For Each rng In .RefersToRange
            If Not IsEmpty(rng) Then
                If rng.Offset(0, -1).Value = sCountry Then
                    If InStr(1, sList, rng.Value, vbTextCompare) = 0 Then
                        If Len(sList) > 0 Then sList = sList & "|"
                        sList = sList & rng.Value
                    End If
                End If
            End If
        Next
    End With
    Me.states.List = Split(sList, "|")
End Sub

Private Sub Worksheet_Activate()
    Dim sList As String
    Dim rng As Range
    With ThisWorkbook.Names("Country")
        For Each rng In .RefersToRange
            If Not IsEmpty(rng) Then
                If InStr(1, sList, rng.Value, vbTextCompare) = 0 Then
                    If Len(sList) > 0 Then sList = sList & "|"
                    sList = sList & rng.Value
                End If
            End If
        Next
    End With
    Me.countries.List = Split(sList, "|")
    countries_Change ' <-- This is better User experience
End Sub