Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.
Es gibt den einen oder anderen Bug in Microsoft Access, der nicht als solcher identifiziert werden kann, weil man einfach nicht herausfindet, wie man ein Fehlverhalten reproduzierbar auslöst. Im vorliegenden Fall ist es einem unserer findigen Kollegen gelungen, einen Bug zu erkennen, der bisher nach unserer Recherche noch nicht dokumentiert wurde. Es handelt sich um einen Bug, der je nach Konstellation mal gar keine Auswirkungen hat und mal schwere Folgen mit sich bringen kann. Den Auslöser zu identifizieren ist auch alles andere als trivial – aber wir haben ihn gleich im Titel präsentiert: Wenn die Höhe eines Unterformulars gleich 0 wird, entlädt Access das Formular. Welche Schritte zum Nachvollziehen nötig sind, welche Folgen dies haben kann und wie sich das Problem beheben lässt, erläutern wir in diesem Beitrag.
Video passend zu diesem Artikel:
Eigentlich kann das gar nicht sein, dachte sich der Access-Entwickler Stefan M. (Name von der Redaktion geändert). Irgendwie spielt das Formular verrückt: Der Timer im Unterformular funktioniert nicht mehr, Variablen werden geleert, obwohl es keinen unbehandelten Laufzeitfehler gab (Stefan M. achtet sehr auf die Behandlung von Fehlern). Zumindest hat sein Kunde dieses Verhalten geschildert – er selbst hatte keinen Schimmer, wie er das Verhalten reproduzieren sollte.
Schließlich setzte er sich selbst mit dem Kunden zusammen und schaute sich an, was dieser in der Praxis mit dem Formular veranstaltet. Schließlich zeigte sich, dass wann immer das merkwürdige Verhalten auftrat, der Kunde die Höhe des Formulars verkleinert hatte, damit er zwar noch den Kopfbereich des Formulars sehen konnte, gleichzeitig aber genug Platz für andere Formulare verfügbar war. Es musste also irgendetwas mit der Höhe des Formulars zu tun haben.
Zurück am eigenen Rechner setzte Stefan M. sich hin und testete die halbe Nacht. Irgendwann hatte er den Fehler identifiziert: Wann immer er das Formular so klein machte, dass der Detailbereich nicht mehr zu sehen war, wurden die Variablen geleert und die aktuelle Markierung des Datensatzes im Unterformular wurde zurückgesetzt. Die erste Erkenntnis war: Das Unterformular musste auf irgendeine Art entladen worden sein. Einige Experimente später hatte er die Konstellation ermittelt, die zum Fehler führt – wir werden diese nun nachstellen.
Reproduzieren des Problems
Ausgangspunkt ist die folgende Situation: Wir verwenden ein Haupt- und ein Unterformular. Das Unterformular befindet sich im Detailbereich des Hauptformulars. Im Hauptformular sind außerdem Formularkopf und -fuß aktiviert. Diese Bereiche müssen nicht sichtbar sein, können also die Höhe 0 aufweisen – es reicht, dass sie aktiviert sind.
In unserem Beispiel zeigen wir im Detailbereich und im Unterformular noch Kategorien und die darin enthaltenen Produkte an – das ist kein dekoratives Beiwerk, sondern nötig für das Nachvollziehen des Beispiels (siehe Bild 1).
Bild 1: Entwurf des problembehafteten Formulars
Um zu zeigen, dass das Formular zu einem bestimmten Zeitpunkt entladen wird, haben wir zunächst das Ereignis Beim Entladen des Unterformulars in Form der folgenden Ereignisprozedur implementiert:
Private Sub Form_Unload(Cancel As Integer) MsgBox "Das Formular wird entladen." End Sub
Sobald das Formular entladen wird, sollte also diese Meldung erscheinen. Damit ließ sich schnell ermitteln, zu welchem Zeitpunkt das Formular entladen wurde – nämlich genau dann, wenn wir die Höhe des Formulars so verkleinert haben, dass der Detailbereich nicht mehr sichtbar war (siehe Bild 2).
Bild 2: Der Bug tritt genau beim Erreichen der Höhe 0 des Detailbereichs auf.
Unterformular entladen – die Folgen
Nachdem die Ursache gefunden war, galt es, die Folgen zu untersuchen. Hier gibt es zumindest die folgenden Probleme:
- Der Datensatzzeiger im Unterformular wird wieder auf den ersten Datensatz gesetzt.
- Filter im Unterformular werden gelöscht.
- Variablen, die im Klassenmodul des Unterformulars deklariert sind, werden geleert.
Das haben wir wie folgt belegt. Der erste Teil ist der Timer. Wir haben die Eigenschaft Zeitgeberintervall auf 1.000 eingestellt (die Einheit ist Millisekunden, also wird das Timer-Ereignis einmal pro Sekunde ausgelöst).
Außerdem haben wir für die Ereigniseigenschaft Bei Zeitgeber die folgende Ereignisprozedur hinterlegt:
Private Sub Form_Timer() Me.Parent.txtTimer = Now Me.Parent.txtTest = strTest End Sub
Diese schreibt bei jedem Aufruf des Timer-Ereignisses, also einmal pro Sekunde, das aktuelle Datum und die aktuelle Zeit in das Textfeld txtTimer. Außerdem schreibt sie den Wert einer Variablen namens strTest in das Textfeld txtTest. Diese Variable deklarieren wir wie folgt im Klassenmodul des Unterformulars:
Dim strTest As String
Beim Laden des Unterformulars wollen wir die Variable strTest erstmalig füllen und außerdem in ein weiteres Textfeld namens txtLoadUnload den Text Load und Datum und Zeit des Ladens eintragen.
Private Sub Form_Load() strTest = "Wert der Variablen strTest" Me.Parent.txtLoadUnload = "Load " & Now Me.Parent.txtTest = strTest End Sub
Damit sieht der Inhalt des Formulars wie in Bild 3 aus. Das erste Textfeld enthält den Text Load …, das zweite liefert sekündlich die aktuelle Zeit und das dritte wird regelmäßig mit dem Inhalt der Variablen strTest gefüllt.
Bild 3: Das Formular direkt nach dem Öffnen
Um nun auch die Auswirkungen des Entladens des Formulars zu demonstrieren, kommentieren wir die MsgBox in der Prozedur für das Ereignis Beim Entladen aus und fügen eine Anweisung hinzu, die den Text im obersten Textfeld auf Unload … ändert:
Private Sub Form_Unload(Cancel As Integer) ''MsgBox "Das Formular wird entladen." Me.Parent.txtLoadUnload = "UnLoad " & Now End Sub
Wenn wir nun die Höhe des Detailbereichs minimieren, zeigt das oberste Textfeld sofort den Text Unload … an, was zeigt, dass die Form_Unload-Prozedur ausgelöst wurde.
Weitere Experimente
Wir sehen nun, dass das Unload-Ereignis ausgelöst wurde und somit alle Variablen geleert wurden. Weitere Ergebnisse sind:
- Wenn wir im Unterformular den zweiten Datensatz markieren, die Höhe des Detailbereichs minimieren und diesen dann wieder vergrößern, ist wieder der erste Datensatz im Unterformular markiert.
- Wenn wir im Unterformular einen Filter anwenden, der beispielsweise nur den ersten Datensatz anzeigt, und den Detailbereich des Hauptformulars verkleinern und wieder vergrößern, ist der Filter wieder entfernt.
- Andererseits bleibt eine einmal getätigte Sortierung im Unterformular erhalten.
Lösungen des Problems
Eine Lösung dieses Problems sahen wir zunächst nicht. Selbst das Setzen des Parameters Cancel auf den Wert True im Unload-Ereignis des Unterformulars hat keinerlei Auswirkung – das Formular wird dennoch entladen.
Die einzige Möglichkeit schien, die offensichtlichen Fehler und Probleme zu identifizieren und diese per Workaround zu beheben – also zum Beispiel Variablen in der Code behind-Klasse des Hauptformulars zu deponieren, den aktuellen Filter in einer Variablen zu speichern und wiederherzustellen, wenn das Formular entladen wurde oder auch die Position des Datensatzzeigers zu speichern und wiederherzustellen, wenn das Unterformular wieder sichtbar wird.
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
Testzugang
eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel
diesen und alle anderen Artikel mit dem Jahresabo