Excel VBA数据验证下拉列表(模块化子模块-无硬代码)

Excel VBA数据验证下拉列表(模块化子模块-无硬代码),excel,vba,validation,dropdown,Excel,Vba,Validation,Dropdown,我想通过VBA EXCEL代码创建数据验证列表,每个验证都来自一个动态更新的列表(例如,如果将项目添加到验证源列表,则范围将按代码更新,而不是手动更新) 我有很多这样的个人验证 首先,我用硬代码范围为每个验证创建了单独的VBA子系统,但这不是模块化的,代码用类似的代码重复,每次需要更新源和目标范围或添加新的验证时,都不容易维护。它对编码错误很敏感,必须提醒自己应该在代码中的具体位置写入范围。 我想要一个通用的、模块化的VBA验证列表,我可以继续使用,而不必一次又一次地重复相同的代码结构 我有一个

我想通过VBA EXCEL代码创建数据验证列表,每个验证都来自一个动态更新的列表(例如,如果将项目添加到验证源列表,则范围将按代码更新,而不是手动更新)

我有很多这样的个人验证

首先,我用硬代码范围为每个验证创建了单独的VBA子系统,但这不是模块化的,代码用类似的代码重复,每次需要更新源和目标范围或添加新的验证时,都不容易维护。它对编码错误很敏感,必须提醒自己应该在代码中的具体位置写入范围。 我想要一个通用的、模块化的VBA验证列表,我可以继续使用,而不必一次又一次地重复相同的代码结构

我有一个带有验证组合框的“数据”表和一个带有验证列表的“信息”表

下面是一个VBA验证结构的示例,该结构具有硬编码的工作表和单元格范围。每次重写都让人头疼:

Public Sub HardcodedValidate()
Dim lastRowSource10 As Long
Dim rangeCombo10  As Range
Const F1_TransalteTo As String = "O"
Const F2_TransalteTo As String = "E"
    lastRowCombo10 = 9999
    lastRowSource10 = Transalte.Cells(Transalte.Rows.Count, "F").End(xlUp).Row
    Set rangeCombo10 = Phones.Range(F2_TransalteTo & "2:" & F2_TransalteTo & lastRowCombo10)
    With rangeCombo10.Validation
        .Delete
        .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
             xlBetween, Formula1:="=Transalte!$F$2:$F$" & lastRowSource10
        .IgnoreBlank = True
        .InCellDropdown = True
        .InputTitle = vbNullString
        .ErrorTitle = vbNullString
        .InputMessage = vbNullString
        .ErrorMessage = vbNullString
        .ShowInput = True
        .ShowError = True
    End With
End Sub

所以基本上你找到了一种使用范围变量的方法?是的,你可以这么说。我认为这是一种使代码可读性产生巨大差异的做法。但我不知道你为什么在SOOk上发布这篇文章,我承认这不是诺贝尔奖的解决方案,但这是一个真正的问题,我很困惑,在网上找不到,所以我想它可能会帮助初学者,或者节省一些时间,或者学习好的做法。
Option Explicit

'' Validation list with scrollable dropdown.
'' * General Sub without hardcoded specific ranges (modular).
'' * No empty cells at the end of each dropdown.
'' * Calculated Source LastRow.
'' * Sub RunGeneralValidate is wrapet with NoUpdate YesUpdate subs for fast run.
'' * Sub RunGeneralValidate is wrapet with Unprotect and re-protect subs for Worksheet that is initially protected.
'' See at the end an example of Call of main sub by RunGeneralValidate

Public Sub GeneralValidate( _
ByVal sheetSource As Worksheet, ByVal columnSource As String, ByVal firstRowSource As Long, _
ByVal sheetCombo As Worksheet, ByVal columnCombo As String, ByVal firstRowCombo As Long, ByVal lastRowCombo As Long)

Dim rangeSource As Range
Dim rangeCombo As Range
Dim lastRowSource As Long

   lastRowSource = sheetSource.Cells(sheetSource.Rows.Count, columnSource).End(xlUp).Row

    Set rangeCombo = sheetCombo.Range(columnCombo & firstRowCombo & ":" & columnCombo & lastRowCombo)
    Set rangeSource = sheetSource.Range("$" & columnSource & "$" & firstRowSource & ":$" & columnSource & "$" & lastRowSource)
    
    With rangeCombo.Validation
        .Delete ''delete previous validation
        .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
             xlBetween, Formula1:="=" & "'" & sheetSource.Name & "'" & "!" & rangeSource.Address
        .IgnoreBlank = True
        .InCellDropdown = True
        .InputTitle = vbNullString
        .ErrorTitle = vbNullString
        .InputMessage = vbNullString
        .ErrorMessage = vbNullString
        .ShowInput = True
        .ShowError = True
    End With
        
End Sub


Public Sub NoUpdate()
    Application.Cursor = xlWait
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Application.Calculation = xlCalculationManual
    Application.DisplayAlerts = False
End Sub


Public Sub YesUpdate()
    Application.Cursor = xlDefault
    Application.Calculation = xlCalculationAutomatic
    Application.EnableEvents = True
    Application.DisplayAlerts = True
    Application.ScreenUpdating = True
End Sub


Public Sub ProtectAll()
' Protect all to dis-allow modifications if locked
'' UserInterfaceOnly allows VBA code to modify locked cells.

    Dim ws As Worksheet
    For Each ws In ThisWorkbook.Sheets
        If ws.ProtectContents = False Then
                ws.EnableSelection = xlNoRestrictions
                    ws.Protect Password:="1234", _
                               Contents:=True, AllowInsertingColumns:=False, AllowInsertingRows:=False, _
                               AllowDeletingColumns:=False, AllowDeletingRows:=False, UserInterfaceOnly:=True, _
                               AllowFormattingCells:=True, AllowFormattingColumns:=True, AllowFormattingRows:=True, _
                               AllowFiltering:=False, AllowSorting:=False, AllowInsertingHyperlinks:=True, _
                               DrawingObjects:=False, Scenarios:=True, AllowUsingPivotTables:=False
                               
         End If
    Next
End Sub

'Unprotectall to unlock cells and allow modifications
Public Sub UnprotectAll()
On Error Resume Next
    Dim ws As Worksheet
    For Each ws In ThisWorkbook.Sheets
   If ws.ProtectContents = True Then
        ws.Unprotect "1234"
        ws.Cells.Locked = False
    End If
    Next ws
End Sub

Public Sub RunGeneralValidate()
''Example of running the subs
Dim Info As Worksheet
Dim Data As Worksheet

Call NoUpdate
Call UnprotectAll

Call GeneralValidate(Info, "A", 2, _
                     Data, "D", 4, 999)
                     
Call GeneralValidate(Info, "B", 2, _
                     Data, "E", 4, 999)

Call GeneralValidate(Info, "C", 2, _
                     Data, "F", 4, 999)

Call ProtectAll
Call YesUpdate

End Sub