多码合一Worksheet_Change

Integrating Multiple Codes into One Worksheet_Change

我正在尝试将多个功能整合为一个 worksheet_change。我之前能够集成 3 个函数(全部与 hiding/unhiding 行有关),但是,我无法添加允许下拉列表中多个 select 离子的函数。

我已经尝试将新的多重 selection 代码添加到以前存在的代码中,它没有给我错误,但它不会 运行。在一个完美的世界中,它会保留 hiding/unhiding 功能,并允许在已识别的行中使用多个 select 离子。

Private Sub Worksheet_Change(ByVal Target As Range)

ActiveSheet.Activate

If Not Application.Intersect(Range("C10:AA10"), Range(Target.Address)) 

Is Nothing Then
    Select Case Target.Value

    Case Is = "Select One": Rows("14:58").EntireRow.Hidden = True
                         Rows("10").EntireRow.Hidden = False
    Case Is = "1": Rows("17:58").EntireRow.Hidden = True
                        Rows("14:16").EntireRow.Hidden = False
    Case Is = "2":  Rows("20:58").EntireRow.Hidden = True
                        Rows("14:19").EntireRow.Hidden = False
    Case Is = "3": Rows("23:58").EntireRow.Hidden = True
                        Rows("14:22").EntireRow.Hidden = False
    Case Is = "4":  Rows("26:58").EntireRow.Hidden = True
                        Rows("14:25").EntireRow.Hidden = False
    Case Is = "5": Rows("29:58").EntireRow.Hidden = True
                        Rows("14:28").EntireRow.Hidden = False
    Case Is = "6":  Rows("32:58").EntireRow.Hidden = True
                        Rows("14:31").EntireRow.Hidden = False
    Case Is = "7": Rows("35:58").EntireRow.Hidden = True
                        Rows("14:34").EntireRow.Hidden = False
    Case Is = "8":  Rows("38:58").EntireRow.Hidden = True
                        Rows("14:37").EntireRow.Hidden = False
    Case Is = "9": Rows("41:58").EntireRow.Hidden = True
                        Rows("14:40").EntireRow.Hidden = False
    Case Is = "10":  Rows("44:58").EntireRow.Hidden = True
                        Rows("14:43").EntireRow.Hidden = False
    Case Is = "11": Rows("47:58").EntireRow.Hidden = True
                        Rows("14:46").EntireRow.Hidden = False
    Case Is = "12":  Rows("50:58").EntireRow.Hidden = True
                        Rows("14:49").EntireRow.Hidden = False
    Case Is = "13": Rows("30:58").EntireRow.Hidden = True
                        Rows("14:52").EntireRow.Hidden = False
    Case Is = "14":  Rows("56:58").EntireRow.Hidden = True
                        Rows("14:55").EntireRow.Hidden = False
    Case Is = "15":  Rows("14:58").EntireRow.Hidden = False
End Select
End If
If Not Intersect(Range("C66:AA66"), Target) Is Nothing Then
    Select Case Target.Value
    Case "GBP", "USD", "Yuan", "EUR", "LRD", "Select One"
        Rows("67").Hidden = True
    Case "Other"
        Rows("67").Hidden = False

    End Select
End If
If Not Intersect(Range("C11:AA11"), Target) Is Nothing Then
    Select Case Target.Value
    Case "$"
        Rows("13").Hidden = True
        Rows("12").Hidden = False
    Case "%"
        Rows("13").Hidden = False
        Rows("12").Hidden = True
    Case "Select One"
        Rows("13").Hidden = True
        Rows("12").Hidden = True

    End Select
End If
Dim Oldvalue As String
Dim Newvalue As String
Application.EnableEvents = True
On Error GoTo Exitsub
If Target.Row = "15",”18”,”21” Then
  If Target.SpecialCells(xlCellTypeAllValidation) Is Nothing Then
GoTo Exitsub
  Else: If Target.Value = "" Then GoTo Exitsub Else
    Application.EnableEvents = False
    Newvalue = Target.Value
    Application.Undo
    Oldvalue = Target.Value
      If Oldvalue = "" Then
        Target.Value = Newvalue
      Else
        If InStr(1, Oldvalue, Newvalue) = 0 Then
            Target.Value = Oldvalue & ", " & Newvalue
      Else:
        Target.Value = Oldvalue
      End If
    End If
  End If
End If
 Application.EnableEvents = True
Exitsub:
Application.EnableEvents = True

End Sub

我希望它能够继续 hiding/unhiding 基于 select 离子的给定行,并允许从行中的下拉列表中选择多个 select在代码中概述。代码没有给我报错,但是multi-select没有运行

我想我明白你想做什么,我希望这些评论能对你的代码有所帮助。所以一些评论...

  1. Always use Option Explicit。不管你在webz上找到什么示例代码,养成这个习惯对你以后都有很大的帮助。
  2. 在你的代码中使用中间变量是一个很大的帮助,使代码成为 self-documenting。分配临时值和对象没有惩罚,因此请利用它。
  3. 将逻辑块分离成单独的子例程或函数。这使您的代码 "functionally isolated" —— 这意味着每个代码块都有一个特定的焦点,如果您需要更改它,您只需在一个位置进行更改。它还使您的代码更易于阅读,而无需上下滚动以了解整体逻辑。

对于您的 Worksheet_Change 事件代码,我可以将逻辑简化为更容易理解的流程:

Option Explicit

Private Sub Worksheet_Change(ByVal target As Range)
    Dim groupsRange As Range
    Dim currencyRange As Range
    Dim valuesRange As Range
    Set groupsRange = ActiveSheet.Range("C10:AA10")
    Set currencyRange = ActiveSheet.Range("C66:AA66")
    Set valuesRange = ActiveSheet.Range("C11:AA11")

    If Not Intersect(groupsRange, target) Is Nothing Then
        ShowActiveGroups target
    ElseIf Not Intersect(currencyRange, target) Is Nothing Then
        ShowCurrency target
    ElseIf Not Intersect(valuesRange, target) Is Nothing Then
        ShowValues target
    End If

    If target.Count > 1 Then Exit Sub

    If (target.Row = 15) Or (target.Row = 18) Or (target.Row = 21) Then
        CheckMultiSelect target
    End If
End Sub

显然,我可能无法获得您的范围的 "point"(使用 "groups"、"currency"、"values"),但您应该使用描述性名称,可以更轻松地理解逻辑在某些部分起作用的原因和原因。

Worksheet_Change 事件中调用的 Subs 的代码被放置在一个单独的模块中,并且所有代码都被标记为 Public。他们每个人都有相似的逻辑,这里有一些东西在起作用。

  1. 在每个逻辑块中(即在本例中的 Sub 代码中),您应该完成 确切 正在引用哪个工作表的步骤。始终 fully qualify your range references (see #5) 至关重要。最简单的方法(不需要很长的复合语句)是使用中间变量。

因此,在上面调用的每个 "Show" 例程中,我都设置了对目标单元格(导致 Worksheet_Change 事件的单元格)的 Worksheet 的引用。

Dim targetWS As Worksheet
Set targetWS = target.Parent
  1. 尝试为看似 "random" 的数字或在工作表上下文之外没有实际意义的值定义常量。

在您的例子中,您引用了许多不同的行并且 hiding/unhiding 它们。我不知道为什么。但是,如果您可以 "name" 代码中的行,它可能更有意义。以下是我使用的一些示例:

Const RED_GROUP_1 As String = "14:58"
Const RED_GROUP_2 As String = "10"
Const GREEN_GROUP_1 As String = "17:58"
Const GREEN_GROUP_2 As String = "14:16"

因此前三个 "Show" 例程可能如下所示:

Public Sub ShowActiveGroups(ByRef target As Range)
    Dim targetWS As Worksheet
    Set targetWS = target.Parent

    Const RED_GROUP_1 As String = "14:58"
    Const RED_GROUP_2 As String = "10"
    Const GREEN_GROUP_1 As String = "17:58"
    Const GREEN_GROUP_2 As String = "14:16"

    With targetWS
        Select Case target.Value
            Case "Select One"
                .Rows(RED_GROUP_1).EntireRow.Hidden = True
                .Rows(RED_GROUP_2).EntireRow.Hidden = False
            Case 1
                .Rows(GREEN_GROUP_1).EntireRow.Hidden = True
                .Rows(GREEN_GROUP_2).EntireRow.Hidden = False
            Case 2
                .Rows("20:58").EntireRow.Hidden = True
                .Rows("14:19").EntireRow.Hidden = False

            ' ...

            Case Else
                '--- what should we do if it's not a valid value?
        End Select
    End With
End Sub

Public Sub ShowCurrency(ByRef target As Range)
    Dim targetWS As Worksheet
    Set targetWS = target.Parent

    Const CURRENCY_LINE As String = "67"

    With targetWS
        Select Case target.Value
            Case "GBP", "USD", "Yuan", "EUR", "LRD", "Select One"
                .Rows(CURRENCY_LINE).EntireRow.Hidden = True
            Case "Other"
                .Rows(CURRENCY_LINE).EntireRow.Hidden = False
            Case Else
                '--- what should we do if it's not a valid value?
        End Select
    End With
End Sub

Public Sub ShowValues(ByRef target As Range)
    Dim targetWS As Worksheet
    Set targetWS = target.Parent

    Const MONEY_LINE As String = "13"
    Const PERCENT_LINE As String = "12"

    With targetWS
        Select Case target.Value
            Case "$"
                .Rows(MONEY_LINE).EntireRow.Hidden = True
                .Rows(PERCENT_LINE).EntireRow.Hidden = False
            Case "%"
                .Rows(MONEY_LINE).EntireRow.Hidden = False
                .Rows(PERCENT_LINE).EntireRow.Hidden = True
            Case "Select One"
                .Rows(MONEY_LINE).EntireRow.Hidden = True
                .Rows(PERCENT_LINE).EntireRow.Hidden = True
            Case Else
                '--- what should we do if it's not a valid value?
        End Select
    End With
End Sub

最后,我总是对您在 webz 上找到的 data-validation/multi-select 代码感到困惑。所以我扔进了我使用的那个有几个轻微的模组。此代码也进入常规代码模块。

Public Sub CheckMultiSelect(ByRef target As Range)
    Dim targetWS As Worksheet
    Set targetWS = target.Parent

    On Error Resume Next
    Dim dvCheck As Range
    Set dvCheck = targetWS.Cells.SpecialCells(xlCellTypeAllValidation)
    If dvCheck Is Nothing Then Exit Sub

    Application.EnableEvents = False
    '--- only allow multi-select if the cell has defined data validation
    If Not Intersect(dvCheck, target) Is Nothing Then
        Dim currentValue As String
        Dim oldValue As String
        currentValue = target.Value
        Application.Undo
        oldValue = target.Value
        If oldValue = vbNullString Then
            target.Value = currentValue
        Else
            If InStr(1, oldValue, currentValue) = 0 Then
                target.Value = oldValue & "," & currentValue
            Else
                If currentValue = vbNullString Then
                    target.Value = vbNullString
                Else
                    target.Value = oldValue
                End If
            End If
        End If
    End If
    Application.EnableEvents = True
End Sub

在工作表模块和常规代码模块中使用上面的代码,我成功地能够执行您原始问题中的一些操作。