Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 6/2006.

Unser Angebot für Sie!

Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'!

Diesen Beitrag twittern

Kurzinformationen

Zusammenfassung

Erstellen Sie eine Funktion, die je nach Bedarf eine neue Objektvariable erstellt oder eine bestehende zurückgibt.

Techniken

VBA

Voraussetzungen

Access 2000 und höher

Beispieldatei

BestaendigeObjektvariablen.mdb

Shortlink

417

Beständige Objektvariablen

André Minhorst, Duisburg

Objektvariablen benötigen Sie immer wieder. Manchmal werden diese sogar in mehreren Routinen eines einzigen Moduls eingesetzt - etwa eine Objektvariable mit einem Verweis auf ein ActiveX- oder ein MSForms-Steuerelement. Aus Performancegründen deklariert man diese oft modulweit - was aber auf Dauer nicht immer gut geht. Access im Unternehmen stellt eine Alternative vor.

Es gibt eine ganze Reihe von Gründen, dafür zu sorgen, dass eine Objektvariable einen Verweis auf ein Objekt über längere Zeit hält. Zwei davon sind Stabilität und Performance. Die beiden folgenden Beispiele zeigen, wie Sie eine scheinbar ständige Verfügbarkeit von Objektvariablen und den referenzierten Objekten erreichen und warum Sie dies tun sollten.

Fehler zerstören Verweise

Wer gelegentlich mit Objekten wie ActiveX-Steuerelementen arbeitet und die Vorzüge von
IntelliSense genießen möchte, deklariert im VBA-Code eine Objektvariable mit dem Schlüsselwort WithEvents.

Üblicherweise erfolgt die Deklaration modulweit, sodass man der Objektvariable den Verweis auf das Steuerelement nur einmal beim Öffnen des zugrunde liegenden Formulars setzen muss und ihn beim Schließen wieder zerstören kann. Betrachten Sie folgendes Beispiel (s. Beispieldatenbank, Formular frmTreeView): Hier enthält ein Formular ein TreeView-Steuerelement namens ctlTreeView, für das mit folgender Zeile im Formularmodul eine Objektvariable deklariert wird (s. Abb. 1):

Dim WithEvents objTreeView As MSComctlLib.TreeView

pic001.tif

Abb. 1: Das TreeView-Steuerelement des Beispielformulars wird in VBA per Objektvariable referenziert.

Die Zuweisung und gegebenenfalls das Füllen mit Daten erfolgt im Ereignis Beim Laden und sieht etwa wie folgt aus:

Private Sub Form_Load(Cancel As Integer)

Set objTreeView = Me!ctlTreeView.Object

With objTreeView

.Nodes.Add , , „A001“, _
„Ein verwaister Knoten ...“

.Nodes.Add , , „A002“, _
„... bleibt nie lang allein.“

End With

End Sub

Andere Routinen, wie etwa die durch die Schaltfläche cmdKontentextAusgeben, greifen dann über die Objektvariable auf das Objekt zu:

Private Sub cmdKnotentextAusgeben_Click()

MsgBox objTreeView.SelectedItem.FullPath

End Sub

Wo also liegt nun das Problem? Dieses taucht genau dann auf, wenn ein unbehandelter Fehler im Formular auftaucht und der Benutzer die anschließende Fehlermeldung (s. Abb. 2) mit einem Klick auf Beenden quittiert: Access verliert dann nämlich alle in Objektvariablen gespeicherten Verweise und reagiert beim Aufruf der nächsten Routine, die mit der Objektvariablen objTreeView auf das TreeView-Steuerelement zugreifen möchte, mit einem weiteren Fehler. Die Stabilität der Anwendung ist somit endgültig dahin, ein vernünftiges Arbeiten mit dem fehlerhaften Formular ist erst nach dem Schließen und erneuten Öffnen wieder möglich. Dies können Sie mit folgender Vorgehensweise verhindern (davon abgesehen, dass Sie natürlich alle Fehler per VBA abfangen sollten - aber manchmal finden die Benutzer eben doch noch eine Lücke ...).

pic002.tif

Abb. 2: Auf die Meldung unbehandelter Fehler reagieren Benutzer üblicherweise mit einem Klick auf die Schaltfläche Beenden.

Property mit Verweis-Check

Der Clou dieser Lösung liegt darin, dass man im kompletten Modul nicht auf die Objektvariable selbst zugreift, sondern auf eine Property-Prozedur, die entweder einen neuen Verweis auf das Objekt erstellt und diesen oder einen bestehenden Verweis zurückgibt. Dazu benötigen Sie neben der eigentlichen Objektvariable, die hier mTreeView heißt, die passende Property Get-Prozedur:

Dim mTreeView As MSComctlLib.TreeView

Private Property Get objTreeViewB()
As MSComctlLib.TreeView

If mTreeView Is Nothing Then

Set mTreeView = Me.ctlTreeView.Object

End If

Set objTreeViewB = mTreeView

End Property

Damit sparen Sie sich erstens das Füllen der Objektvariablen mit dem Verweis auf das Steuerelement beim Öffnen des Formulars und stellen die Funktion des Objektverweises für das komplette Modul sicher. Um das TreeView-Steuerelement im Ereignis Beim Laden zu füllen, greifen Sie direkt auf die Property objTreeViewB zu.
Diese liefert dann mit Sicherheit einen Verweis auf das passende Steuerelement zurück. Dazu prüft die Property-Prozedur zunächst, ob mTreeView, also die eigentliche Objektvariable, einen Verweis enthält, und erstellt diesen gegebenenfalls neu.

Noch besser ist, dass man diese Property-Prozedur genau wie eine Objektvariable handhaben kann - selbst IntelliSense wird damit unterstützt:

Private Sub Form_Load(Cancel As Integer)

With objTreeViewB

.Nodes.Add , , „A001“, _
„Ein verwaister Knoten ...“

.Nodes.Add , , „A002“, _
„... bleibt nie lang allein.“

End With

End Sub

Auch die Routine zum Ausgeben eines Elements greift auf diese Weise auf die Objektvariable zu:

Private Sub _
cmdKnotentextAusgebenOhneFehler_Click()

MsgBox objTreeViewB.SelectedItem.FullPath

End Sub

Die hier beschriebene Konfiguration finden Sie im Formular frmTreeView_BestaendigesObjekt.

Performance optimieren mit beständigen Objektverweisen

Noch interessanter ist sicher die Performance-Verbesserung, die sich durch den Einsatz von beständigen Objektverweisen erzielen lässt.

Wenn Ihre Datenbank beispielsweise Daten enthält, auf die Sie sehr oft zugreifen, macht es Sinn, ein passendes Recordset zu erzeugen und in einem geöffneten Zustand zu halten. Dies ist zum Beispiel in Zusammenhang mit Konfigurationsparametern für die aktuelle Anwendung interessant.

Das Beispiel aus Listing 1 verwendet die Tabelle aus Abb. 3 als Grundlage. Die Datensätze der Tabelle sollen in einem Recordset abgebildet und fortan über dieses ermittelt werden – Sie fragen also die Datensätze der Tabelle einmal zu Beginn der Anwendung ab und greifen danach nicht mehr auf diese zu. Dabei ist das Beispiel allerdings etwas komplizierter als das vorherige: Die Property-Prozedur soll nicht nur einfach das Recordset-Objekt liefern, sondern direkt einen konkreten Wert. Und das geht so: Die Variable mRstParameter speichert das Recordset mit den Datensätzen der Tabelle tblParameter. Die Property Get-Prozedur erwartet als Parameter den Namen des Parameters. Sie prüft dann, ob das Recordset-Objekt mRstParameter schon erzeugt wurde, und holt dies gegebenenfalls nach. Dann sucht sie mit der FindFirst-Methode nach dem Datensatz mit dem gesuchten Parameternamen und gibt, soweit dieser Parameter vorhanden ist, dessen Wert zurück. Sie finden diese Routine im Modul mdlGlobal der Beispieldatenbank.

Listing 1: Parameter aus einem beständigen Recordset statt aus einer Tabelle beziehen

Dim mRstParameter As DAO.Recordset

Public Property Get Anwendungsparameter(strParameter As String) As String

    If mRstParameter Is Nothing Then

         Set mRstParameter = CurrentDb.OpenRecordset(„tblParameter“, dbOpenDynaset)

     End If

     mRstParameter.FindFirst „Parameter = ‚“ & strParameter & „‘“

     If mRstParameter.NoMatch Then

         Anwendungsparameter = „“

     Else

         Anwendungsparameter = mRstParameter.Fields(„Wert“)

     End If

End Property

pic003.tif

Abb. 3: Diese Tabelle dient als Grundlage für das „beständige“ Recordset.

Aktuelle Datenbank schnell zur Hand

Das bekannteste Beispiel für solche „beständigen Objektverweise“ dürfte das von Michael Kaplan sein: Er verwendet eine Property Get-Prozedur, um einen Verweis auf das von der Funktion CurrentDB gelieferte Database-Objekt von Access zu liefern oder einen bereits erzeugten Verweis zu erstellen:

Dim mDB As DAO.Database

Public Property Get CurrentDBC()

     If mDB Is Nothing Then

         Set mCurrentDB = CurrentDB

     End If

     CurrentDBC = mDB

End Property

Wenn Sie diese Routine in einem öffentlichen Standardmodul deklarieren, können Sie statt der Funktion CurrentDB die Property Get-Prozedur CurrentDBC verwenden – sie greift nach dem ersmaligen Zuweisen immer auf einen bestehenden Verweis auf das aktuelle Database-Objekt zu.

Kompletten Artikel lesen?

Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

E-Mail:

Download

Download

Die .zip-Datei enthält folgende Dateien:

BestaendigeObjektvariablen.mdb

Beispieldateien downloaden

© 2003-2015 André Minhorst Alle Rechte vorbehalten.