VBA
Gebruikersformulieren
Zoeken…
Best practices
Een UserForm
is een klassemodule met een ontwerper en een standaardinstantie . De ontwerper kan worden benaderd door op Shift + F7 te drukken terwijl de code-behind wordt bekeken , en de code-behind kan worden geopend door op F7 te drukken terwijl u de designer bekijkt.
Werk elke keer met een nieuw exemplaar.
Als een klassemodule is een formulier daarom een blauwdruk voor een object . Omdat een formulier status en gegevens kan bevatten, is het een betere gewoonte om met een nieuw exemplaar van de klasse te werken, in plaats van met het standaard / globale exemplaar:
With New UserForm1
.Show vbModal
If Not .IsCancelled Then
'...
End If
End With
In plaats van:
UserForm1.Show vbModal
If Not UserForm1.IsCancelled Then
'...
End If
Werken met de standaardinstantie kan leiden tot subtiele bugs wanneer het formulier wordt gesloten met de rode "X" -knop en / of wanneer Unload Me
wordt gebruikt in de code-behind.
Implementeer de logica elders.
Een formulier moet zich alleen bezighouden met presentatie : een Click
handler die verbinding maakt met een database en een geparametriseerde query uitvoert op basis van gebruikersinvoer, doet teveel dingen .
Implementeer in plaats daarvan de applicatielogica in de code die verantwoordelijk is voor het weergeven van de vorm, of nog beter, in speciale modules en procedures.
Schrijf de code zodanig dat het UserForm alleen verantwoordelijk is om te weten hoe gegevens moeten worden weergegeven en verzameld: waar de gegevens vandaan komen of wat er daarna met de gegevens gebeurt, is hem niet van belang.
Beller moet zich niet bezig houden met bedieningselementen.
Maak een goed gedefinieerd model voor het formulier om mee te werken, hetzij in zijn eigen speciale klassenmodule, of ingekapseld in de code van het formulier achter zichzelf - leg het model bloot met Property Get
procedures en laat de klantcode hiermee werken: dit maakt de vorm een abstractie over bedieningselementen en hun nitty-gritty details, waardoor alleen de relevante gegevens aan de klantcode worden blootgesteld.
Dit betekent code die er zo uitziet:
With New UserForm1
.Show vbModal
If Not .IsCancelled Then
MsgBox .Message, vbInformation
End If
End With
In plaats van dit:
With New UserForm1
.Show vbModal
If Not .IsCancelled Then
MsgBox .txtMessage.Text, vbInformation
End If
End With
Behandel de QueryClose-gebeurtenis.
Formulieren hebben meestal een knop Sluiten en aanwijzingen / dialoogvensters hebben de knoppen OK en Annuleren ; kan de gebruiker het formulier sluiten met behulp van het besturingsvak van het formulier (de rode "X" -knop), die standaard de formulierinstantie vernietigt (nog een goede reden om elke keer met een nieuwe instantie te werken ).
With New UserForm1
.Show vbModal
If Not .IsCancelled Then 'if QueryClose isn't handled, this can raise a runtime error.
'...
End With
End With
De eenvoudigste manier om de QueryClose
gebeurtenis af te handelen is om de parameter Cancel
te stellen op True
en vervolgens het formulier te verbergen in plaats van het te sluiten :
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Cancel = True
Me.Hide
End Sub
Op die manier zal de "X" -knop het exemplaar nooit vernietigen en heeft de beller veilig toegang tot alle openbare leden.
Verbergen, niet sluiten.
De code die een object maakt, moet verantwoordelijk zijn voor het vernietigen ervan: het is niet de verantwoordelijkheid van het formulier om zichzelf te ontladen en te beëindigen.
Vermijd het gebruik van Unload Me
in de code achter van een formulier. Call Me.Hide
plaats daarvan, zodat de roepende code nog steeds het object kan gebruiken dat is gemaakt wanneer het formulier wordt gesloten.
Noem dingen.
Gebruik het eigenschappenvenster ( F4 ) om elk besturingselement op een formulier zorgvuldig een naam te geven. De naam van een besturingselement wordt gebruikt in de code achter, dus tenzij u een refactoring-tool gebruikt die dit aankan, zal het hernoemen van een besturingselement de code verbreken - dus het is veel gemakkelijker om dingen meteen te doen, dan proberen om precies uit te puzzelen voor welke van de 20 tekstvakken waar TextBox12
staat.
Traditioneel worden UserForm-besturingselementen benoemd met voorvoegsels in Hongaarse stijl:
-
lblUserName
eenLabel
controle die een gebruikersnaam aangeeft. -
txtUserName
voor eenTextBox
besturingselement waar de gebruiker een gebruikersnaam kan invoeren. -
cboUserName
voor eenComboBox
besturingselement waar de gebruiker een gebruikersnaam kan invoeren of kiezen. -
lstUserName
voor eenListBox
besturingselement waarbij de gebruiker een gebruikersnaam kan kiezen. -
btnOk
ofcmdOk
voor eenButton
het label "Ok".
Het probleem is dat wanneer bijvoorbeeld de UI wordt vernieuwd en een ComboBox
verandert in een ListBox
, de naam moet veranderen om na te denken van de nieuwe controle-type: het is beter om de naam van de controles voor wat ze vertegenwoordigen, in plaats van na hun controle-type - de ontkoppelen code uit de UI zoveel mogelijk.
-
UserNameLabel
voor een alleen-lezen label dat een gebruikersnaam aangeeft. -
UserNameInput
Voer een besturingselement in waarmee de gebruiker een gebruikersnaam kan invoeren of kiezen. -
OkButton
voor een opdrachtknop met het label "Ok".
Welke stijl ook wordt gekozen, alles is beter dan alle besturingselementen hun standaardnamen te laten. Consistentie in naamgevingsstijl is ook ideaal.
Query verwerkenSluiten
De QueryClose
gebeurtenis wordt QueryClose
wanneer een formulier wordt gesloten, of het nu via gebruikersactie of programmatisch is. De parameter CloseMode
bevat een VbQueryClose
enum-waarde die aangeeft hoe het formulier is gesloten:
Constante | Beschrijving | Waarde |
---|---|---|
vbFormControlMenu | Formulier wordt gesloten als reactie op gebruikersactie | 0 |
vbFormCode | Formulier wordt gesloten als reactie op een Unload instructie | 1 |
vbAppWindows | Windows-sessie is afgelopen | 2 |
vbAppTaskManager | Windows Taakbeheer sluit de hosttoepassing | 3 |
vbFormMDIForm | Niet ondersteund in VBA | 4 |
Voor een betere leesbaarheid is het het beste om deze constanten te gebruiken in plaats van hun waarde direct te gebruiken.
Een annuleerbaar gebruikersformulier
Een formulier gegeven met een knop Annuleren
De code-achter van het formulier kan er zo uitzien:
Option Explicit
Private Type TView
IsCancelled As Boolean
SomeOtherSetting As Boolean
'other properties skipped for brievety
End Type
Private this As TView
Public Property Get IsCancelled() As Boolean
IsCancelled = this.IsCancelled
End Property
Public Property Get SomeOtherSetting() As Boolean
SomeOtherSetting = this.SomeOtherSetting
End Property
'...more properties...
Private Sub SomeOtherSettingInput_Change()
this.SomeOtherSetting = CBool(SomeOtherSettingInput.Value)
End Sub
Private Sub OkButton_Click()
Me.Hide
End Sub
Private Sub CancelButton_Click()
this.IsCancelled = True
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
this.IsCancelled = True
Me.Hide
End If
End Sub
De belcode kan dan het formulier weergeven en weten of het is geannuleerd:
Public Sub DoSomething()
With New UserForm1
.Show vbModal
If .IsCancelled Then Exit Sub
If .SomeOtherSetting Then
'setting is enabled
Else
'setting is disabled
End If
End With
End Sub
De eigenschap IsCancelled
retourneert True
wanneer op de knop Annuleren wordt geklikt of wanneer de gebruiker het formulier sluit met behulp van het besturingselement .