Manchmal zeigt das Hauptformular die gleichen Daten wie das Unterformular an – beispielsweise, wenn das Unterformular als übersichtsliste die Daten in der Datenblattansicht liefert und ein Wechseln des Datensatzes im Unterformular zur Anzeige der Details des gleichen Datensatzes in im Hauptformular führen soll. Soll dies auch umgekehrt der Fall sein, also das beim Wechsel des Datensatzes im Hauptformular der entsprechende Datensatz im Unterformular markiert wird, wird es kompliziert. Mögliche Probleme und die Auflösung liefert dieser Beitrag.
Beispieldatenbank
Die Beispiele dieses Artikels finden Sie in der Datenbank 1706_HauptUndUnterformularSynchron.accdb.
Beispielkonstellation
Wir wollen die Daten einer Tabelle namens tblHersteller aus unserer Beispiellösung Handyverwaltung herausnehmen und an diesem Beispiel zeigen, wie Haupt- und Unterformular synchron gehalten werden können. Dazu legen wir zunächst ein neues Unterformular namens sfmHersteller an, das die Abfrage qryHerstellerBezeichnungNachAlphabet als Datenherkunft verwendet. Diese Abfrage liefert nur die beiden Felder HerstellerID und Bezeichnung der Tabelle tblHersteller, und zwar alphabetisch nach dem Inhalt des Feldes Bezeichnung sortiert.
Das Hauptformular frmHersteller verwendet eine ähnliche Abfrage namens qryHerstellerNachBezeichnung, welche allerdings alle Felder der Tabelle tblHersteller enthält. Auch hier gibt es eine Sortierung nach dem Feld Bezeichnung.
Das Unterformular platzieren wir wie in Bild 1 im Hauptformular. Nun wollen wir, dass das Hauptformular und das Unterformular immer den gleichen Datensatz anzeigen beziehungsweise dass im Unterformular immer der Datensatz markiert ist, der aktuell im Hauptformular angezeigt wird und umgekehrt.
Bild 1: Haupt- und Unterformular zur Anzeige der Daten aus der gleichen Datenherkunft
Erster Versuch
Dabei stellen wir uns nun vor, dass Folgendes funktionieren könnte und probieren es aus. Für das Ereignis Beim Anzeigen des Hauptformulars legen wir die folgende Ereignisprozedur an:
Private Sub Form_Current() Me!sfmHersteller.Form.Recordset!HerstellerID = Me!HerstellerID End Sub
Diese Prozedur stellt also den Datensatzmarkierer für das Recordset im Unterformular auf den Datensatz ein, dessen Primärschlüsselfeld HerstellerID dem passenden Wert im Hauptformular entspricht.
Für das entsprechende Ereignis des Unterformulars verwenden wir eine ganz ähnliche Ereignisprozedur, welche die folgende Zeile enthält:
Private Sub Form_Current() Me.Parent.Recordset.FindFirst "HerstellerID = " & Me!HerstellerID End Sub
Diese versucht, den Datensatzzeiger im Recordset des Hauptformulars auf den Datensatz einzustellen, dessen HerstellerID im Unterformular ausgewählt wurde. öffnen wir nun das Formular in der Formularansicht, erhalten wir die Ansicht aus Bild 2 – es klappt also wie gewünscht.
Bild 2: Beim Anzeigen erscheinen die Datensätze im Haupt- und Unterformular synchron.
Das ist auch der Fall, wenn wir zwischen den Datensätzen im Haupt- oder im Unterformular navigieren. Es tritt erst ein Problem auf, wenn wir den Datensatzzeiger im Haupt- oder Unterformular auf einen neuen, leeren Datensatz verschieben.
Dann erhalten wir die Fehlermeldung aus Bild 3. Der Grund für diese Fehlermeldung ist, dass Me!HerstellerID zu diesem Zeitpunkt, also beim Anlegen eines neuen Datensatzes, den Wert Null enthält. Dadurch sieht der Ausdruck, der als Kriterium der FindFirst-Methode verwendet wird, wie folgt aus:
Bild 3: Fehler beim Anzeigen eines neuen, leeren Datensatzes
HerstellerID =
Diesen Ausdruck kann Access nicht auswerten, also wird die Fehlermeldung aus der Abbildung generiert.
ändern wir die beiden Ereignisprozeduren also etwas ab, um die Fehlermeldung zu verhindern. Dazu fassen wir die Angabe des Wertes Me!Hersteller einfach mit der Funktion Nz ein und geben als zweiten Parameter den Wert 0 an, was dafür sorgt, dass die Funktion den Wert 0 liefert, wenn HerstellerID den Wert Null aufweist:
'Hauptformular Private Sub Form_Current() Me!sfmHersteller.Form.Recordset.FindFirst "HerstellerID = " & Nz(Me!HerstellerID, 0) End Sub 'Unterformular Private Sub Form_Current() Me.Parent.Recordset.FindFirst "HerstellerID = " & Nz(Me!HerstellerID, 0) End Sub
Dies führt nun immerhin dazu, dass beim Ansteuern eines neuen, leeren Datensatzes im Haupt- oder Unterformular kein Fehler mehr ausgelöst wird. Allerdings finden wir hier ein etwas merkwürdiges Verhalten vor, denn wenn Sie etwa mit der Tabulator-Taste im Unterformular vom letzten auf den neuen, leeren Datensatz wechseln, springt der Datensatzzeiger auf den ersten Datensatz im Unterformular. Das Gleiche geschieht auch manchmal, wenn Sie mit der Maus von einem anderen Datensatz auf den neuen, leerenDatensatz wechseln. Wenn Sie hingegen soeben auf den letzten Datensatz gewechselt sind und der Datensatzzeiger dadurch auf den ersten Datensatz gesprungen ist und dann mit der Maus auf den neuen, leeren Datensatz klicken, verbleibt der Datensatzzeiger auf diesen Datensatz.
Was geschieht im Hintergrund genau Um das herauszufinden, haben wir den beiden Ereignisprozeduren jeweils eine Debug.Print-Anweisung hinzugefügt, welche einen Hinweis auf die jeweilige Prozedur im Haupt- oder Unterformular im Direktfenster ausgibt:
'Hauptformular Private Sub Form_Current() Debug.Print "Hauptformular_Current" Me!sfmHersteller.Form.Recordset.FindFirst "HerstellerID = " & Nz(Me!HerstellerID, 0) End Sub 'Unterformular Private Sub Form_Current() Debug.Print "Unterformular_Current" Me.Parent.Recordset.FindFirst "HerstellerID = " & Nz(Me!HerstellerID, 0) End Sub
Wenn wir das Formular nun öffnen, werden die Ereignisse in dieser Reihenfolge ausgelöst:
Unterformular_Current Hauptformular_Current
Das Verschieben des Datensatzzeigers über das Ereignis im Unterformular sorgt also dafür, dass auch das Ereignis Beim Anzeigen im Hauptformular ausgelöst wird. Obwohl dieses wiederum den Datensatzzeiger im Unterformlar verschiebt, löst dies nicht nochmal das Ereignis Beim Anzeigen im Unterformular aus. Offensichtlich hat Access einen Automatismus eingebaut, der Zirkelbezüge zwischen Prozeduren schnell erkennt und nach einmaliger Ausführung abbricht. Dabei wird die Prozedur im Hauptformular genau nach dem Aufruf von FindFirst im Unterformular ausgelöst. Nach dem Abarbeiten der Prozedur im Hauptformular wird dann noch die letzte Zeile der Prozedur im Unterformular erledigt (siehe Bild 4).
Bild 4: Ablauf der beiden Prozeduren beim öffnen des Formulars
Wenn Sie mit der Tabulator-Taste von einem Datensatz zum nächsten wechseln, löst dies jeweils die gleichen Ereignisse aus. Wenn wir auf diese Weise allerdings auf dem neuen, leeren Datensatz landen, werden folgende Ereignisse ausgelöst:
Unterformular_Current Hauptformular_Current Unterformular_Current
Dabei löst FindFirst im Unterformular die Prozedur im Hauptformular aus und FindFirst im Hauptformular nochmals die entsprechende Prozedur im Unterformular. Erst danach bricht die Abarbeitung der Ereignisprozeduren ab.
Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access [basics]:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 400 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein: