Datensatznavigation per Ribbon mit Klasse

Navigieren in Formularen per Ribbon

Bild 1: Navigieren in Formularen per Ribbon

Im Beitrag „Datensatznavigation per Ribbon“ (www.access-im-unternehmen.de/1415) haben wir die Steuerelemente zur Navigation durch die Datensätze aus der Navigationsleiste eines Formulars in das Ribbon verlegt. Damit das Ribbon die Position des Datensatzzeigers anzeigt, enthält das Formular eine Variable und drei Ereignisprozeduren. Diesen Code müssten wir in jedes weitere Formular kopieren, welches das Ribbon anzeigen soll. Wie wir es in eine Klasse auslagern, sodass jedes Formular nur noch eine Variable und eine Prozedur benötigt, zeigt der vorliegende Beitrag.

Im oben genannten Beitrag haben wir eine praktische Lösung vorgestellt, welche die Elemente der Navigationsleiste eines Formulars direkt im Ribbon anzeigt. Dadurch können wir die eingebauten Elemente durch Setzen von Navigationsschaltflächen auf Nein ausblenden und stellen dem Benutzer gut sichtbare Steuerelemente zur Verfügung (siehe Bild 1).

Navigieren in Formularen per Ribbon

Bild 1: Navigieren in Formularen per Ribbon

Ereignisse des Formulars in einer Klasse behandeln

Das Formular frmKunden enthält in der Lösung aus dem Vorgängerbeitrag die Variable lngPos und die Ereignisprozeduren Form_Current, Form_AfterUpdate und Form_Delete.

Form_Current und Form_AfterUpdate rufen die Methode Invalidate auf, damit das Ribbon seine Elemente aktualisiert. Form_Delete speichert die Position des Datensatzzeigers vor dem Löschen eines Datensatzes.

Form_Current stellt die Position anschließend wieder her. Die Ribbondefinition und die Bilder übernehmen wir aus dem Vorgängerbeitrag. Die Callbackprozeduren im Modul mdlRibbons erweitern wir im Abschnitt Das Formular mit dem Fokus ermitteln.

Dieser Code ist in allen Formularen, die das Ribbon verwenden, identisch. Deshalb lagern wir ihn in eine Klasse aus, die auf die Ereignisse des Formulars reagiert. Aus dem Formular frmKunden entfernen wir ihn danach.

Dazu deklarieren wir in der Klasse eine Variable des Typs Form mit dem Schlüsselwort WithEvents. Für diese Variable stellt Access die Ereignisse des Formulars bereit. Dafür können wir Ereignisprozeduren in der Klasse anlegen.

Außerdem muss die jeweilige Ereigniseigenschaft des Formulars den Wert [Event Procedure] haben, damit das Formular seine Ereignisse an die Klasse meldet.

Wenn ein Ereignis in einem Formular definiert wurde, wird dies weiterhin ausgeführt und nicht ersetzt. Es feuern dann beide Ereignisse (Klasse und Formular selbst). Das Einstellen erledigt die Klasse selbst, sobald sie das Formular erhält.

Die Klasse clsNavigationWrapper anlegen

Im VBA-Editor legen wir ein neues Klassenmodul an und nennen es clsNavigationWrapper. Es beginnt mit zwei Variablen:

Private WithEvents m_Form As Form
Private lngPos As Long

Die Variable m_Form verweist später auf das Formular und stellt dessen Ereignisse bereit. In der Variablen lngPos speichern wir wie im Vorgängerbeitrag die Position des Datensatzzeigers vor dem Löschen eines Datensatzes. Die Klasse erhält das Formular über die Property Set-Prozedur Form:

Public Property Set Form(frm As Form)
    Set m_Form = frm
    With m_Form
        .OnCurrent = "[Event Procedure]"
        .OnActivate = "[Event Procedure]"
        .AfterUpdate = "[Event Procedure]"
        .OnDelete = "[Event Procedure]"
        .OnClose = "[Event Procedure]"
    End With
End Property

Die Prozedur speichert den Verweis auf das Formular in der Variablen m_Form. Danach stellt sie die Eigenschaften OnCurrent, OnActivate, AfterUpdate, OnDelete und OnClose des Formulars auf den Wert [Event Procedure] ein.

Mit diesen Werten ruft Access die Ereignisprozeduren der Klasse auf, auch wenn das Formular selbst keine enthält. Das Formular benötigt allerdings ein Klassenmodul, das wir für das Erzeugen der Klasse im Formular anlegen.

Die Ereignisse OnCurrent, OnActivate und AfterUpdate führen zum selben Ergebnis: Das Ribbon soll seine Elemente neu abrufen. Das erledigt die Prozedur RibbonAktualisieren:

Private Sub RibbonAktualisieren()
    If Not objRibbon_Navigation Is Nothing Then
        objRibbon_Navigation.Invalidate
    End If
End Sub

Die Prozedur ruft die Methode Invalidate der Variablen objRibbon_Navigation auf. Diese Variable haben wir wie im Vorgängerbeitrag im Modul mdlRibbons deklariert.

Zuvor prüft die Prozedur, ob die Variable bereits einen Verweis auf das Ribbon enthält. Beim ersten Öffnen eines Formulars tritt das Ereignis OnCurrent nämlich ein, bevor die Prozedur onLoad_Navigation die Variable füllt. Der Aufruf der Methode Invalidate würde dann einen Fehler auslösen. Wenn mehrere Formulare geöffnet sind, die dasselbe Ribbon verwenden, soll das Ribbon den Zustand des aktiven Formulars anzeigen.

Die Callbackprozeduren im Modul mdlRibbons ermitteln das Formular dazu zunächst über die Eigenschaft ActiveForm des Objekts Screen. Beim Wechsel zu einem anderen Formular tritt das Ereignis OnActivate ein. Die Prozedur m_Form_Activate aktualisiert dann das Ribbon:

Private Sub m_Form_Activate()
    RibbonAktualisieren
End Sub

Ohne diese Prozedur zeigt das Ribbon nach dem Wechsel zwischen zwei geöffneten Formularen weiter die Position des zuvor aktiven Formulars an. Das zeigen wir im Abschnitt Das Ribbon in den Formularen prüfen.

Damit kommen wir zum Ereignis Beim Anzeigen, das wir mit m_Form_Current implementieren. Das Textfeld im Ribbon zeigt die Position des Datensatzzeigers und die Anzahl der Datensätze, getrennt durch einen Schrägstrich (/).

Nach dem Löschen eines Datensatzes liefert die Eigenschaft AbsolutePosition des Formular-Recordsets zunächst den Wert -1 oder löst den Fehler 3167 aus.

Die Prozedur prüft deshalb, ob die Eigenschaft den Wert -1 hat. Falls ja, stellt sie die Position aus der Variablen lngPos wieder her, die die Prozedur m_Form_Delete vor dem Löschen gespeichert hat:

Private Sub m_Form_Current()
    On Error Resume Next
    If m_Form.Recordset.AbsolutePosition = -1 Then
        m_Form.Recordset.AbsolutePosition = lngPos
    End If
    RibbonAktualisieren
End Sub

Löst das Lesen der Eigenschaft AbsolutePosition den Fehler 3167 aus, setzt VBA die Ausführung wegen On Error Resume Next mit der Anweisung im Then-Zweig fort.

Die Prozedur stellt die Position damit sowohl bei dem Wert -1 als auch bei dem Fehler 3167 wieder her. Die Anweisung On Error Resume Next unterdrückt bis zum Ende der Prozedur jeden weiteren Fehler. Würden wir die Position nicht wiederherstellen, zeigte das Textfeld im Ribbon nach dem Löschen die Position 0 an.

Das Ereignis AfterUpdate tritt ein, nachdem der Benutzer einen neuen oder geänderten Datensatz gespeichert hat. Die Prozedur m_Form_AfterUpdate gleicht zunächst die Position des Recordsets mit der des Formulars ab und aktualisiert danach das Ribbon:

Private Sub m_Form_AfterUpdate()
    m_Form.Recordset.Bookmark = m_Form.Bookmark
    RibbonAktualisieren
End Sub

In den Beispieldaten mit 100 Kunden steht der Datensatzzeiger des Recordsets nach dem Speichern eines neuen Datensatzes noch auf dem bisher letzten Datensatz.

Ohne den Abgleich zeigt das Textfeld im Ribbon deshalb 100/101 statt 101/101 an.

Für den Abgleich weisen wir der Eigenschaft Bookmark des Recordsets das Lesezeichen aus der Eigenschaft Bookmark des Formulars zu.

Die Prozedur m_Form_Delete speichert die Position des Datensatzzeigers in der Variablen lngPos, bevor Access den Datensatz löscht:

Private Sub m_Form_Delete(Cancel As Integer)
    lngPos = m_Form.Recordset.AbsolutePosition
End Sub

Das Formular speichert die Instanz der Klasse in einer Variablen, wie wir im Abschnitt Die Klasse im Formular erzeugen zeigen.

Die Instanz verweist über die Variable m_Form wiederum auf das Formular.

Damit dieser gegenseitige Verweis nach dem Schließen nicht bestehen bleibt, stellen wir die Variable m_Form beim Schließen des Formulars auf den Wert Nothing ein:

Private Sub m_Form_Close()
    Set m_Form = Nothing
End Sub

Den Verweis auf das Ribbon speichern

Die Prozedur onLoad_Navigation im Modul mdlRibbons weist der Variablen objRibbon_Navigation den Verweis auf das Ribbon zu.

Access ruft die Prozedur beim Laden des Ribbons auf. Den Verweis übergibt es im Parameter ribbon:

Sub onLoad_Navigation(ribbon As IRibbonUI)
    Set objRibbon_Navigation = ribbon
End Sub

Die Klasse im Formular erzeugen

Wir müssen noch klären, wo wir die Klasse instanziieren. Dafür käme die Prozedur onLoad_Navigation infrage, die Access beim Laden des Ribbons aufruft. Sie könnte das aktive Formular an eine neue Instanz der Klasse übergeben.

Ob Access die Prozedur für jedes Formular aufruft, prüfen wir mit einer Ausgabe im Direktbereich:

Sub onLoad_Navigation(ribbon As IRibbonUI)
    Set objRibbon_Navigation = ribbon
    Debug.Print "onLoad_Navigation fuer " _
        & Screen.ActiveForm.Name
End Sub

Wir starten Access neu, öffnen das Formular frmKunden, schließen es, rufen es erneut auf und starten danach das Formular frmGanzLeer. Der Direktbereich enthält nur eine Zeile:

onLoad_Navigation fuer frmKunden

In der Beispieldatenbank ruft Access die Prozedur onLoad_Navigation nur beim ersten Öffnen eines Formulars mit diesem Ribbon auf. Danach verwendet Access das geladene Ribbon weiter. Jedes Formular muss deshalb die Instanz der Klasse selbst erzeugen. Die Zeile mit Debug.Print entfernen wir wieder.

Zum Erzeugen der Instanz deklarieren wir im Klassenmodul des Formulars die Variable objNavigation des Typs clsNavigationWrapper. Die Ereignisprozedur Form_Load erzeugt darin eine Instanz der Klasse und übergibt ihr mit dem Schlüsselwort Me das Formular:

Private objNavigation As clsNavigationWrapper
Private Sub Form_Load()
    Set objNavigation = New clsNavigationWrapper
    Set objNavigation.Form = Me
End Sub

Die Klasse kann die Eigenschaft OnLoad nicht selbst einstellen, weil die Instanz der Klasse erst in Form_Load entsteht.

Deshalb muss die Eigenschaft OnLoad des Formulars den Wert [Event Procedure] enthalten. Access trägt ihn ein, wenn wir die Prozedur über das Eigenschaftenblatt des Formulars anlegen, wobei auch das Klassenmodul des Formulars entsteht.

Außer der Eigenschaft RibbonName benötigt ein Formular nur den Code aus obigem Listing.

Für jedes weitere Formular, welches das Ribbon anzeigen soll, stellen Sie die Eigenschaft RibbonName auf den Wert Navigation und die Eigenschaft OnLoad auf den Wert [Event Procedure] ein. Danach fügen Sie den Code in das Klassenmodul des Formulars ein.

Das Ribbon in den Formularen prüfen

Öffnen wir das Formular frmKunden in der Datenblattansicht und markieren den dritten Datensatz, zeigt das Textfeld im Ribbon die Position 3/100 an (siehe Bild 2).

Das Ribbon im Formular frmKunden mit dem dritten Datensatz

Bild 2: Das Ribbon im Formular frmKunden mit dem dritten Datensatz

Das Formular frmGanzLeer zeigt die leere Tabelle Tabelle1 an, und die Eigenschaft RecordsetType hat den Wert Snapshot. Die Datensatzgruppe enthält also keine Datensätze und lässt sich nicht aktualisieren.

Access im Unternehmen

Unser exklusives Angebot für Dich!

Access im Unternehmen
13,25 € im Monat*

(Gilt für den Abschluss eines Jahres-Abonnements im ersten Jahr, danach 189,-/Jahr)

Hier geht’s weiter →

Die ersten 4 Wochen kostenlos testen – voller Zugriff auf alle Artikel, vollständigen Code und Beispieldatenbanken. Kein Risiko: Wenn es nicht passt, kündigst Du einfach innerhalb der ersten vier Wochen.

PayPal VISA Mastercard SEPA
Kostenlos & unverbindlich

Hast Du eine konkrete Frage zu Deiner eigenen Access-Anwendung?

Vielleicht stellt Deine Anwendung Dich vor eine Herausforderung, zu der Du bisher keine Lösung findest. Schlechte Performance, kein ausreichender Zugriffsschutz, Du bist unsicher über Dein Datenmodell oder Dein Code liefert unerklärliche Fehler?

In unserem kostenlosen Access-Audit schaut sich André Minhorst persönlich gemeinsam mit Dir Deine Lösung per Zoom an – und zeigt Dir, wo Datenmodell, VBA-Code, Ergonomie und Sicherheit Optimierungspotenzial bieten.

Jetzt kostenloses Access-Audit anfordern →