PDA

Vollständige Version anzeigen : Klassenmodul mit ausgelagerten Events und Mehrfachinstanziierung über Collection


JPA
31.01.2015, 21:49
Heute möchte ich mich dem Thema selbstdefinierte Klassenmodule widmen, mit der besonderheit nicht nur Funktionalität auszulagern, sondern auch die Events von Formularen und deren Controls. Des weiteren möchte ich aufzeigen, wie mehrere Klasseninstanziierungen in einer Collection verwaltet werden können.
Hinweis: Diese Technik steht ab der Version Access 2002 zur Verfügung.

Nehmen wir mal an, wir möchten die Anzahl der Änderungen in einem Textfeld-Steuerelement (ggf. sogar in sämtlichen) zählen und diese Anzahl soll über ein Steuerelement im Formular angezeigt werden.

Angenommen unser Eingabe-Steuerelement trägt den Namen Suchname und die Anzahl der Änderungen soll im Steuerelement mit dem Namen txtAnzAenderungen ausgegeben werden.
Eine simple Aufgabe!
Und hier ist dann auch gleich die einfache Lösung:
Private Sub Suchname_AfterUpdate()
Me.txtAnzAenderungen = Me.txtAnzAenderungen + 1
End Sub

Sollte jedoch diese Funktionalität für mehrer Textfelder (z.B. alle im Formular) benötigt werden, dann muss im Code für jedes einzelne Textfeld eine Event-Prozedur angelegt werden. Das wird sehr unübersichtlich und erzeugt schnell langen Code.
Vielleicht wird diese Funktionalität sogar in anderen Formularen auch noch benötigt.
Und wieder muss der exakt gleiche Code vervielfältigt werden.
Und plötzlich wird unsere einfache Lösung zu einem riesen Konstrukt!

Möchten wir das? Nein! Daher lagern wir die Funktionalität und auch die Events in einem Klassenmodul einfach aus.
Unser selbstdefinierte Klassenmodul mit dem Namen clsEventManager sieht dann so aus:
Option Compare Database
Option Explicit

Dim cTargetControl As Access.TextBox
Private WithEvents cTxtBox As Access.TextBox
Private WithEvents cFrm As Access.Form

Public Function Ini(MyTextBox As Access.TextBox _
, Optional TargetControl As Access.TextBox) As Boolean

'Hier wird auf das Formular vom Steuerelement MyTextBox referenziert
Set cFrm = MyTextBox.Parent
'Aktivierung der gewünschten Event-Prozeduren vom Formular
cFrm.AfterUpdate = "[Event Procedure]"
cFrm.OnUndo = "[Event Procedure]"

'Hier wird auf das Steuerelement MyTextBox referenziert
Set cTxtBox = MyTextBox
'Aktivierung der gewünschten Event-Prozedur vom Steuerelement
cTxtBox.AfterUpdate = "[Event Procedure]"

Set cTargetControl = TargetControl
Ini = True
End Function

Private Sub cTxtBox_AfterUpdate()
If Not cTargetControl Is Nothing Then cTargetControl = cTargetControl + 1
End Sub

Private Sub cFrm_AfterUpdate()
'Zähler auf 0 setzen, weil alle Änderugen im Datensatz abgebrochen wurden
If Not cTargetControl Is Nothing Then cTargetControl = 0
End Sub

Private Sub cFrm_Undo(Cancel As Integer)
'Zähler auf 0 setzen, weil alle Änderugen im Datensatz abgebrochen wurden
If Not cTargetControl Is Nothing Then cTargetControl = 0
End Sub

In der Objektvariable cTargetControl ist das Ziel-Textfeld (txtAnzAenderungen) von unserem Formular gespeichert, im welchen die Anzahl der Änderungen ausgegeben wird.
In der Objektvariable cTextBox ist das Textfeld (Suchname) von unserem Formular in dem die Änderungen gemacht werden gespeichert. Damit diese mit Events belegt werden kann, wurde diese mit Private WithEvents dimensioniert.
In der Objektvariable cFrm ist das Formular in dem die Änderungen gemacht werden gespeichert. Diese wurde auch mit Private WithEvents dimensioniert, da wir auch hier Events benötigen.
Die Aktivierung der Events über die Objektvariablen findet mit dem Eintrag ...= "[Event Procedure]" statt.
Das ist im Prinzip das Entscheidende, um Events auslagern zu können.

In unserem Formular muss jetzt nur noch die Klasse aktiviert (instanziiert) werden und dabei das gewünschte Textfeld (über die Funktion Ini) übergeben werden:
Option Compare Database
Option Explicit
Dim EM As clsEventManager

Private Sub Form_Load()
'Klasse wird instanziiert und in der Objektvariable EM gespeichert
Set EM = New clsEventManager

'Die betreffenden Steuerelemente werden der Klasse bekannt gemacht
EM.Ini Me.Suchname, Me.txtAnzAenderungen
End Sub
Wir stellen fest, in unserem Formular werden keine Event-Prozeduren mehr benötigt, die Klasse muss nur einmal instanziiert werden (geschieht hier beim Öffnen des Forms) und alles anderen übernimmt die Klasse inkl. Events!

Möchten wir jetzt mehrere Textfelder mit dieser Funktionalität belegen, dann brauchen wir einfach nur weitere Klassen zu instanziieren. Dies würde dann so aussehen:
Option Compare Database
Option Explicit

Dim EM1 As clsEventManager
Dim EM2 As clsEventManager
Dim EM3 As clsEventManager

Private Sub Form_Load()
Set EM1 = New clsEventManager
EM1.Ini Me.Suchname, Me.txtAnzAenderungen

Set EM2 = New clsEventManager
EM2.Ini Me.Bemerkung, Me.txtAnzAenderungen

Set EM3 = New clsEventManager
EM3.Ini Me.Hobbies, Me.txtAnzAenderungen
End Sub
Und wir sind nun sogar in der Lage diese Funktionalität inkl. Events in weiteren Formularen zu integrieren, lediglich die Textfelder müssen angepasst werden. Cool Sache, oder?!

Was ist aber wenn wir diese Funktionalität auf sehr viele Textfelder setzen möchten, ggf. sogar alle Textfelder vom Formular.
Dafür benötigen wir abermals eine elegante Lösung, und hier kommt die Collection ins Spiel.
Das Prinzip ist recht einfach, über eine Schleife finden wir alle Textfelder vom Formular heraus, und instanziieren für jedes eine Klasse. Die instanziiert Klasse wird dann in einer Collection gespeichert, so wie im nachfolgenden Code beschrieben ist:
Option Compare Database
Option Explicit
'Diese Variable speichert alle Klassenmodule die instanziiert werden
Dim colEM As New Collection

Private Sub Form_Load()
Dim EM As clsEventManager
Dim ctl As Access.Control

'Schleife durch alle Controls im aktuellen Formular
For Each ctl In Me.Controls
If ctl.ControlType = acTextBox Then
'Es handelt sich um ein Textfeld-Steuerelement
Set EM = New clsEventManager
If EM.Ini(ctl, Me.txtAnzAenderungen) Then
'Die instanziierte Klasse wird der Collection gespeichert
colEM.Add Item:=EM, Key:=ctl.Name
End If
Set EM = Nothing 'EM wird nicht mehr benötigt, da in Collection
End If
Next
End Sub

Dieser Code kann nun in jedes Formular integriert werden, lediglich das Textfeld
txtAnzAenderungen muss angepasst werden.

Gruß
JPA