DropdownLists
Manages the dropdown lists of one worksheet. Each list is a one-column ListObject and carries a workbook-level name. Add creates a list, Remove deletes it, ClearList empties it, Update rewrites its values, and Sort and Translate reorder and relabel the entries. SetValidation puts a list behind a range of cells, and AddHyperLink and AddReturnLink link the dropdown worksheet with the cells that use it.
THE REGISTRY
Column C of the worksheet holds the dropdown name and column D the name of its ListObject, both under a header on row 2. Every public member reads those two columns once as a block and answers from that copy for the rest of the call. The copy is dropped when the call ends, so each call reads the columns again.
Depends on: HiddenNames, BetterArray, Checking, increment by default the counter on the number of dropdowns by 1. Everytime a, dropdown is added to the current worksheet. The counter is saved somewhere the, first cell fo the worksheet. It starts at 1., dropdowns in the current dropdown worksheet., Where all the dropdowns should start, sometimes there could be a need, for header for the dropdown (like in custom dropdowns, so we shift one line), The registry that maps a dropdown name to its ListObject name. The dropdown, name is in column C, the ListObject name in column D. Both columns carry a, header on DROPDOWNSTARTROW., Field positions inside one row of the registry block held in memory, Row 1 of the registry block is the column header, so data starts on row 2, Counter start values: the workbook counter starts at 1, the worksheet one at 0, checking objects
Version: 1.0 (2026-02-09)
Factory
Create #
create
Create a new DropdownLists instance
Signature:
Public Function Create(ByVal outsh As Worksheet, Optional ByVal hprefix As String = "dropdown_") As DropdownLists
Initialises a DropdownLists object on the given worksheet. Each dropdown is stored as a one-column ListObject; the header prefix distinguishes multiple dropdown worksheets in the same workbook. On first use the worksheet is formatted (gridlines removed, registry columns created) and an initialisation flag is stored via HiddenNames.
Parameters:
outsh: Worksheet. The worksheet to host the dropdown ListObjects.hprefix: Optional String. Prefix for ListObject header names. Defaults to "dropdown_".
Returns: DropdownLists. The new instance.
Throws:
- ProjectError.ElementNotFound When outsh is Nothing.
Modify
Add #
add
Add a new dropdown to the worksheet
Signature:
Public Sub Add(ByVal listValues As BetterArray, ByVal listName As String, _
Optional ByVal addLabel As Boolean = False, _
Optional ByVal counterPrefix As String = vbNullString, _
Optional ByVal tableStyle As String = "TableStyleLight13")
Creates a one-column ListObject populated with the supplied values, registers the name-to-ListObject mapping, and creates a workbook-level named reference. Optionally writes a visible label above the ListObject and applies a table style. Silently exits when the dropdown already exists. The ListObject name is built before the counters move, so it carries the old workbook number, while the label is built after and carries the new worksheet number.
Parameters:
listValues: BetterArray. String values to populate the ListObject.listName: String. Name to assign to the dropdown.addLabel: Optional Boolean. When True, writes a label above the ListObject. Defaults to False.counterPrefix: Optional String. Prefix for the label text. Defaults to vbNullString.tableStyle: Optional String. Excel table style name. Defaults to "TableStyleLight13".
Remove #
remove
Remove a dropdown from the worksheet
Signature:
Public Sub Remove(ByVal listName As String)
Deletes the ListObject, its workbook-level name reference, the internal registry entry, and decrements both counters. Silently exits when the dropdown does not exist.
Parameters:
listName: String. Dropdown name to remove.
ClearList #
clear-list
Clear entries of a dropdown
Signature:
Public Sub ClearList(ByVal listName As String)
Removes all data rows from the dropdown ListObject without deleting the dropdown itself. Silently exits when the dropdown does not exist.
Parameters:
listName: String. Dropdown name to clear.
Update #
update
Update a dropdown with new values
Signature:
Public Sub Update(ByVal UpdateData As BetterArray, ByVal listName As String, _
Optional ByVal pasteAtBottom As Boolean = False, _
Optional ByVal removeDuplicates As Boolean = True)
Replaces or appends values in the specified dropdown. When pasteAtBottom is True, appends below existing data. Duplicate entries are removed when removeDuplicates is True. Silently exits when the dropdown does not exist or the data is empty.
Parameters:
UpdateData: BetterArray. New values to write.listName: String. Dropdown name to update.pasteAtBottom: Optional Boolean. When True, appends below existing rows. Defaults to False.removeDuplicates: Optional Boolean. When True, removes duplicate entries. Defaults to True.
Sort #
sort
Sort a dropdown ListObject
Signature:
Public Sub Sort(ByVal listName As String, _
Optional ByVal sortOrder As Long = xlAscending)
Sorts the dropdown entries using the specified sort order. Silently exits when the dropdown does not exist.
Parameters:
listName: String. Dropdown name to sort.sortOrder: Optional Long. xlSortOrder enumeration value. Defaults to xlAscending.
Translate #
translate
Translate all dropdowns on the worksheet
Signature:
Public Sub Translate(ByVal trads As Object, Optional ByVal force As Boolean = False, Optional ByVal exclude As String)
Iterates over every registered ListObject and applies the supplied TranslationObject to its data body. Skips translation when the current language matches and force is False. ListObjects whose name contains the exclude substring are skipped.
Parameters:
trads: Object. A TranslationObject providing translations.force: Optional Boolean. When True, translates regardless of language match. Defaults to False.exclude: Optional String. Substring filter to skip matching ListObjects.
Operations
SetValidation #
set-validation
Apply dropdown validation to a Range
Signature:
Public Sub SetValidation(ByVal cellRng As Range, ByVal listName As String, _
Optional ByVal alertType As String = "info", _
Optional ByVal message As String = vbNullString, _
Optional ByVal showError As Boolean = True)
Sets data validation on the target Range using the specified dropdown as the validation source. alertType controls the severity: "info" shows an information alert, "warning" shows a warning, and "error" prevents entry of values outside the list. Silently exits when the dropdown or range does not exist.
Parameters:
cellRng: Range. Target range to validate.listName: String. Dropdown name to use as the validation source.alertType: Optional String. Alert severity ("info", "warning", "error"). Defaults to "info".message: Optional String. Message shown on validation failure. Defaults to vbNullString.showError: Optional Boolean. When True, displays validation feedback. Defaults to True.
AddReturnLink #
add-return-link
Add a return hyperlink on the dropdown header
Signature:
Public Sub AddReturnLink(ByVal listName As String, ByVal returnRng As Range)
Adds a hyperlink on the dropdown label cell that navigates back to the specified range.
Parameters:
listName: String. Dropdown whose label receives the link.returnRng: Range. Target destination of the hyperlink.
AddHyperLink #
add-hyperlink
Add a hyperlink on a cell targeting a dropdown
Signature:
Public Sub AddHyperLink(ByVal listName As String, ByVal linkRng As Range)
Adds a hyperlink on the specified range that navigates to the label cell of the dropdown.
Parameters:
listName: String. Dropdown to navigate to.linkRng: Range. Cell that receives the hyperlink.
Internal members (not exported)
Elements
Wksh #
wksh
Worksheet hosting the dropdown lists
Signature:
Public Property Get Wksh() As Worksheet
Returns: Worksheet. The host worksheet.
Wksh #
wksh-set
Assign the worksheet and initialise the dropdown registry
Signature:
Public Property Set Wksh(ByVal outsh As Worksheet)
On first assignment, formats the worksheet (removes gridlines, creates internal registry columns) and stores an initialisation flag. Resets cached HiddenNames stores on every assignment.
Parameters:
outsh: Worksheet. The worksheet to host dropdown ListObjects.
AllDropdowns #
all-dropdowns
All registered dropdown names
Signature:
Public Property Get AllDropdowns() As BetterArray
Scans the internal registry column and collects every dropdown name into a BetterArray.
Returns: BetterArray. The dropdown name list.
headerPrefix #
header-prefix
Header prefix used for ListObject names
Signature:
Public Property Get headerPrefix() As String
Returns: String. The current prefix.
headerPrefix #
header-prefix-set
Assign the header prefix
Signature:
Public Property Let headerPrefix(ByVal hprefix As String)
Parameters:
hprefix: String. The new prefix value.
Name #
name
Name of the dropdown object
Signature:
Public Property Get Name() As String
Returns the name of the worksheet that hosts the dropdown lists.
Returns: String. The worksheet name.
Registry
RefreshRegistry #
refresh-registry
Read the dropdown registry again from the worksheet
Signature:
Private Sub RefreshRegistry()
A routine that changes the registry calls this once at its start. One call reads the two registry columns a single time, and every lookup after that runs in memory. The copy is dropped first because another DropdownLists object can hold the same worksheet and change the registry in between.
SetValidation and AddLink read the registry and never write it, so they call EnsureRegistry and keep the copy. One SetupPreparation.Prepare makes 56 SetValidation calls, and each forced reload costs two worksheet crossings for bookkeeping alone.
EnsureRegistry #
ensure-registry
Load the registry when no copy is held
Signature:
Private Sub EnsureRegistry()
LoadRegistry #
load-registry
Read the two registry columns into memory in one block
Signature:
Private Sub LoadRegistry()
Reads from the header row down to the last used row of the dropdown name column. Row 1 of the block is the header, so dropdown entries start at REGISTRYFIRSTDATAITEM.
RegistryItem #
registry-item
Read one field of one registry row as text
Signature:
Private Function RegistryItem(ByVal rowIndex As Long, ByVal fieldIndex As Long) As String
Parameters:
rowIndex: Long. Row position inside the registry block.fieldIndex: Long. REGISTRYNAMEITEM or REGISTRYLONAMEITEM.
Returns: String. The stored text, or an empty string when out of range.
RegistryIndexOf #
registry-index-of
Find the registry row that holds a dropdown name
Signature:
Private Function RegistryIndexOf(ByVal listName As String) As Long
Parameters:
listName: String. Dropdown name to look for.
Returns: Long. Row position inside the registry block, or 0 when absent.
RegistryRow #
registry-row
Worksheet row of a registry block position
Signature:
Private Function RegistryRow(ByVal rowIndex As Long) As Long
Parameters:
rowIndex: Long. Row position inside the registry block.
Returns: Long. The 1-based worksheet row.
RegistryFreeRow #
registry-free-row
First worksheet row free for a new registry entry
Signature:
Private Function RegistryFreeRow() As Long
A removed dropdown leaves an empty row behind, and that row is used again before the registry grows.
Returns: Long. The 1-based worksheet row to write on.
HasDropdown #
has-dropdown
Whether a dropdown name is in the registry held in memory
Signature:
Private Function HasDropdown(ByVal listName As String) As Boolean
Parameters:
listName: String. Dropdown name to look for.
Returns: Boolean. True when the name is registered.
MissingDropdown #
missing-dropdown
Report a dropdown that is not on the worksheet
Signature:
Private Function MissingDropdown(ByVal listName As String, ByVal message As String, _
Optional ByVal showTrace As Boolean = True) As Boolean
Logs the given message and prints the debug trace when the dropdown is absent. Callers use the return value to leave at once.
Parameters:
listName: String. Dropdown name to look for.message: String. Text to log when the dropdown is missing.showTrace: Optional Boolean. When True, prints the debug trace. Defaults to True.
Returns: Boolean. True when the dropdown does not exist.
Counters
InternalStore #
internal-store
Lazy-loaded HiddenNames store for workbook or sheet scope
Signature:
Private Property Get InternalStore(Optional ByVal sheetLevel As Boolean = False) As HiddenNames
Returns the cached HiddenNames instance for either the workbook (default) or the worksheet. Creates the store on first access.
Parameters:
sheetLevel: Optional Boolean. When True, returns the worksheet-level store. Defaults to False.
Returns: HiddenNames. The requested store.
CounterName #
counter-name
Stored name of a dropdown counter
Signature:
Private Function CounterName(ByVal sheetLevel As Boolean) As String
Parameters:
sheetLevel: Boolean. True for the worksheet counter, False for the workbook one.
Returns: String. The hidden name holding the counter.
CounterStart #
counter-start
Start value of a dropdown counter
Signature:
Private Function CounterStart(ByVal sheetLevel As Boolean) As Long
Parameters:
sheetLevel: Boolean. True for the worksheet counter, False for the workbook one.
Returns: Long. The value the counter takes when it is created.
CounterStore #
counter-store
Store holding a dropdown counter, created when missing
Signature:
Private Function CounterStore(ByVal sheetLevel As Boolean) As HiddenNames
The counters are shared by every DropdownLists object of the workbook, so they live in HiddenNames and never in memory. Only the store object is cached.
Parameters:
sheetLevel: Boolean. True for the worksheet counter, False for the workbook one.
Returns: HiddenNames. The store that holds the counter.
CounterValue #
counter-value
Read a dropdown counter
Signature:
Private Function CounterValue(ByVal sheetLevel As Boolean) As Long
Parameters:
sheetLevel: Boolean. True for the worksheet counter, False for the workbook one.
Returns: Long. The counter value.
StepCounter #
step-counter
Move one dropdown counter and write it through at once
Signature:
Private Sub StepCounter(ByVal sheetLevel As Boolean, ByVal stepValue As Long)
The worksheet counter never goes below zero. The value is written back to the store on every step because other DropdownLists objects read the same counter.
Parameters:
sheetLevel: Boolean. True for the worksheet counter, False for the workbook one.stepValue: Long. Amount to add, negative to go down.
StepCounters #
step-counters
Move the worksheet and workbook counters together
Signature:
Private Sub StepCounters(ByVal stepValue As Long)
Parameters:
stepValue: Long. Amount to add, negative to go down.
IncrementCounters #
increment-counters
Increment both workbook and worksheet counters
Signature:
Private Sub IncrementCounters()
DecrementCounters #
decrement-counters
Decrement both workbook and worksheet counters
Signature:
Private Sub DecrementCounters()
Helpers
RemoveGridLines #
remove-gridlines
Remove gridlines from a worksheet view
Signature:
Private Sub RemoveGridLines(ByVal sh As Worksheet, Optional DisplayZeros As Boolean = False)
Parameters:
sh: Worksheet. Target worksheet.DisplayZeros: Optional Boolean. When True, displays zeros. Defaults to False.
LastColumn #
last-column
Find the next available column for a new dropdown
Signature:
Private Function LastColumn() As Long
Returns the column index two positions to the right of the rightmost occupied header cell. This leaves a blank separator column between adjacent ListObjects.
Returns: Long. The 1-based column index.
SanitizedListName #
sanitized-list-name
Sanitise a dropdown name for use in ListObject naming
Signature:
Private Function SanitizedListName(ByVal listName As String) As String
Parameters:
listName: String. The dropdown name.
Returns: String. The trimmed and space-replaced name.
ListObjectHeaderName #
list-object-header-name
Build the ListObject header name for a dropdown
Signature:
Private Function ListObjectHeaderName(ByVal listName As String) As String
Parameters:
listName: String. The dropdown name.
Returns: String. The prefixed header name.
CorrespondingWorkbookName #
corresponding-workbook-name
Workbook-level name used for the dropdown reference
Signature:
Private Property Get CorrespondingWorkbookName(ByVal listName As String) As String
Combines the header prefix with the ListObject header name. When no prefix is set, falls back to the DEFAULTNAMEPREFIX constant.
Parameters:
listName: String. The dropdown name.
Returns: String. The workbook-level reference name.
ListObjectName #
list-object-name
ListObject name for a dropdown
Signature:
Private Property Get ListObjectName(ByVal listName As String) As String
Returns the stored ListObject name for an existing dropdown, or generates and registers a new one for a dropdown being created. The workbook counter is what keeps the generated name unique across the whole workbook, so two worksheets can hold a dropdown of the same name.
Parameters:
listName: String. Dropdown name.
Returns: String. The ListObject name.
DropdownListObject #
dropdown-list-object
ListObject that holds the values of a dropdown
Signature:
Private Function DropdownListObject(ByVal listName As String) As ListObject
Parameters:
listName: String. The dropdown name.
Returns: ListObject. The table on the dropdown worksheet.
DropdownLabelCell #
dropdown-label-cell
Cell that carries the label of a dropdown
Signature:
Private Function DropdownLabelCell(ByVal listName As String) As Range
The label sits one row above the header row of the ListObject.
Parameters:
listName: String. The dropdown name.
Returns: Range. The label cell.
FormatLabelCell #
format-label-cell
Write and format the label cell of a dropdown
Signature:
Private Sub FormatLabelCell(ByVal labelCell As Range, ByVal labelText As String, _
ByVal interiorColor As Long, ByVal fontColor As Long)
Used when a dropdown is added, and again after a hyperlink is placed on the label, because adding a hyperlink wipes the text and the format.
Parameters:
labelCell: Range. The cell above the ListObject header.labelText: String. Text to write. An empty text leaves the value alone.interiorColor: Long. Background colour of the cell.fontColor: Long. Colour of the text.
AddLoName #
add-lo-name
Register a dropdown-to-ListObject name mapping
Signature:
Private Sub AddLoName(ByVal listName As String, ByVal loName As String)
Parameters:
listName: String. The dropdown name.loName: String. The corresponding ListObject name.
RemoveLoName #
remove-lo-name
Remove a dropdown-to-ListObject name mapping
Signature:
Private Sub RemoveLoName(ByVal lst As String)
Parameters:
lst: String. The dropdown name to unregister.
Length #
length
Total number of dropdowns on the worksheet
Signature:
Public Property Get Length() As Long
Returns: Long. The dropdown count.
CurrentDropdownLabel #
current-dropdown-label
Build the display label for the next dropdown
Signature:
Private Function CurrentDropdownLabel(ByVal labelPrefix As String) As String
Combines the prefix with the current counter to produce a human-readable label (e.g. "Custom Dropdown 3").
Parameters:
labelPrefix: String. Text prefix for the label.
Returns: String. The assembled label.
Exists #
exists
Check whether a dropdown exists on the worksheet
Signature:
Public Function Exists(ByVal listName As String) As Boolean
Looks only at the registry of this worksheet, so two worksheets can hold a dropdown of the same name without seeing each other.
Parameters:
listName: String. Dropdown name to search for.
Returns: Boolean. True when the dropdown is found.
WorkbookName #
workbook-name
Workbook-level name a dropdown answers to
Signature:
Public Property Get WorkbookName(ByVal listName As String) As String
The name SetValidation points a cell at, and the name any other reader uses to reach the values. It is derived from the list name and the header prefix, so it can be asked for before the dropdown is added.
This is here because a reader outside the class needs the name in a place where building a manager is too costly - a worksheet function called once per formula cell reads the range by this name and nothing else.
Parameters:
listName: String. Dropdown name.
Returns: String. The workbook-level name.
LabelRange #
label-range
Label cell above a dropdown ListObject
Signature:
Public Property Get LabelRange(ByVal listName As String) As Range
Returns the cell directly above the header row of the specified dropdown ListObject. Returns Nothing when the dropdown does not exist.
Parameters:
listName: String. Dropdown name to look up.
Returns: Range. The label cell, or Nothing.
Values #
values
Retrieve the values of a dropdown
Signature:
Public Property Get Values(ByVal listName As String, Optional ByVal includeHeaders As Boolean = False) As BetterArray
Returns a BetterArray of the entries stored in the specified dropdown. Logs a diagnostic note and exits when the dropdown does not exist.
Parameters:
listName: String. Dropdown name to read from.includeHeaders: Optional Boolean. When True, includes the header row. Defaults to False.
Returns: BetterArray. The dropdown entries.
Operations
AddLink #
add-link
Add a hyperlink between a dropdown and a cell
Signature:
Private Sub AddLink(ByVal listName As String, ByVal targetRng As Range, _
Optional ByVal returnLink As Boolean = False)
Creates a hyperlink that navigates between the dropdown label cell and the specified target range. When returnLink is True, the link is placed on the dropdown label pointing at targetRng; when False, the link is placed on targetRng pointing at the dropdown label. Preserves the original cell formatting after link insertion.
Parameters:
listName: String. Dropdown name whose label is involved.targetRng: Range. The other end of the hyperlink.returnLink: Optional Boolean. When True, link is on the dropdown side. Defaults to False.
Checkings
LogInfo #
log-info
Record a diagnostic entry
Signature:
Private Sub LogInfo(ByVal label As String, _
Optional ByVal scope As Byte = checkingNote)
Parameters:
label: String. The message to log.scope: Optional Byte. Severity level. Defaults to checkingNote.
HasCheckings #
has-checkings
Whether the dropdown object has logged diagnostic messages
Signature:
Public Property Get HasCheckings() As Boolean
Returns: Boolean. True when diagnostic entries exist.
CheckingValues #
checking-values
Retrieve the diagnostic log entries
Signature:
Public Property Get CheckingValues() As Object
Returns: Object. An Checking instance, or Nothing.
ShowDebug #
show-debug
Print a debug trace to the Immediate window
Signature:
Private Sub ShowDebug()
ThrowError #
throw-error
Raise a ProjectError-based exception
Signature:
Private Sub ThrowError(ByVal errNumb As Long, ByVal errorMessage As String)
Parameters:
errNumb: Long. ProjectError code.errorMessage: String. Descriptive message.
Throws:
- ProjectError.
Always raises the specified error.
Seal #
seal
Seal the instance so setup setters can no longer be written
Signature:
Public Sub Seal()
GuardNotSealed #
guard-not-sealed
Guard a setup setter against writes after sealing
Signature:
Private Sub GuardNotSealed(ByVal propName As String)
Parameters:
propName: String. Name of the property being guarded.
Used in (50 file(s))
- AnalysisOutput.cls
- AnalysisRanges.cls
- ChoiceKeys.cls
- LLExporter.cls
- LLImporter.cls
- DesignerPreparation.cls
- CustomTable.cls
- LLGeo.cls
- EventLinelist.cls
- Linelist.cls
- LLDataEntry.cls
- DiseaseSheet.cls
- EventMasterSetup.cls
- IDiseaseSheet.cls
- MasterSetupPreparation.cls
- MasterSetupVariables.cls
- SectionBuilder.cls
- VarWriter.cls
- EventSetup.cls
- SetupErrors.cls
- SetupPreparation.cls
- EventsDesignerAdvanced.bas
- EventsDesignerMulti.bas
- HeadlessBuild.bas
- GeoModule.bas
- EventsMasterSetupRibbon.bas
- MasterSetupHelpers.bas
- EventsRibbon.bas
- Exports.bas
- ManageDiseases.bas
- Misc.bas
- TestAnalysisRanges.bas
- TestCrossTableFormula.bas
- TestChoiceKeys.bas
- TestLLExporter.bas
- TestLLImporter.bas
- TestDesignerPreparation.bas
- TestDropdownLists.bas
- TestCustomLinelistFunctions.bas
- TestEventLinelistSheets.bas
- TestLinelist.bas
- TestLLDataEntry.bas
- TestDiseaseIntegration.bas
- TestDiseaseSheet.bas
- TestEventMasterSetup.bas
- TestMasterSetupVariables.bas
- TestSectionBuilder.bas
- TestVarWriter.bas
- TestEventSetup.bas
- TestSetupPreparation.bas