Option Private Module
Option Private Module
should be used in any standard module that doesn't mean to expose its public members to Excel as macros (i.e. Public Sub
procedures) or User-Defined-Functions (i.e. Public Function
procedures).
Without this option, a standard module's public parameterless Sub
procedures appear in Excel's list of available macros, and public Function
procedures appear in Excel's cell "intellisense" as available worksheet functions.
Note that this merely hides a module's members from the macros list: if you type the exact name of a "hidden" procedure, Excel will still run it.
Dim vs Private vs Public
Dim
is a keyword you use for declaring local variables, inside a procedure scope. The keyword is also legal for declaring private, module-level variables, but then you might as well use Private
.
When used for declaring module-level variables, Private
makes that variable only accessible from within the module it's declared in.
When used for declaring module-level variables, Public
makes that variable accessible from anything that has access to the module it's declared in - in a standard module, that means the variable is effectively Global
. In a class (/document/userform/anything else) module, it means the variable holds instance state and is accessible from anything that has access to an instance of that class. Classes that have a predeclaredId, such as UserForm
classes, all have an instance that's globally accessible: avoid storing instance state in this default instance.
Use Worksheet.CodeName
Set wb = Application.ThisWorkbook
Set wsSI = wb.Sheets("SavedInfo")
Set wsCalcs = wb.Sheets("Calcs")
Set wsNarr = wb.Sheets("Narrative")
Set wsEval = wb.Sheets("EvalCL")
Set wsUW = wb.Sheets("UWCL")
Set wsLVBA = wb.Sheets("ListsForVBA")
ThisWorkbook
is the workbook you're looking at - the one that contains your VBA code. The ThisWorkbook
identifier is globally accessible, and Application.ThisWorkbook
is merely a pointer to that object.
Use ThisWorkbook
over Application.ThisWorkbook
, unless you've declared a local variable and named it ThisWorkbook
- then that local variable would be shadowing the global identifier; don't do that. There shouldn't be any reason to need to qualify ThisWorkbook
with Application
.
Now, if any of these worksheets exist at compile-time in ThisWorkbook
, then you don't need any of these variables. Find each sheet in the Project Explorer (Ctrl+R), then hit F4 and give its (Name)
property a meaningful identifier name.
So if you rename Sheet1
to SavedInfoSheet
, then you can access SavedInfoSheet
from anywhere in the code, and you don't ever need to dereference it from the Workbook.Sheets
(or better, Workbook.Worksheets
) collection. The reason for this is that VBA automatically creates a global-scope identifier by the name of whatever identifier you put as the (Name)
property of a Worksheet
module.
If the sheets don't exist at compile-time (i.e. they're created at run-time), then you don't need these variables either, because the code that created them should already have that reference:
Set theNewSheet = theBook.Worksheets.Add
Then you can (and should) pass these worksheet object references around, as parameters, as needed.
There is no worksheet.
What I would like to do is set this up in a Standard Mod so I dont have to continue setting variables for worksheets through all of my UserForms that use the same naming convention for Worksheets they reference
Your forms are running the show. The code that fires them looks like this:
UserForm1.Show
Like any UI, forms are responsible for collecting user input, and showing data to the user. If you find yourself writing userform code-behind that accesses a dozen worksheets (and/or worse, makes them public fields), you're making your form much, much more complicated than it needs to be, and you're treating a full-fledged object as a mere container for procedures, by making its default instance stateful.
This article goes in details about how to fix that. This article pushes the concept further and allows back-and-forth communication between the view and the presenter, and has a download link with a simple example to study (disclaimer: I wrote these articles, and the accompanying example code).
UserForm code done right, looks extremely simple, and is responsible for so little logic, it's boring. In fact, it's not responsible for any logic beyond presentation - all a UserForm should do, is respond to control events, relay control state to some model, and if application logic needs to be executed before the form is closed (e.g. if a command button is clicked but the form should remain open), then it fires an event, and the calling code ("presenter") handles it by triggering the logic that needs to run.
When the dialog is okayed, or when it relays an event to the presenter, code outside the form's code-behind is executed to to the work: the form never needs to know anything about any worksheet.