Bug: Unterformular entlädt bei Bereichshöhe gleich 0

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:

YouTube

Mit dem Laden des Videos akzeptieren Sie die Datenschutzerklärung von YouTube.
Mehr erfahren

Video laden

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).

Entwurf des problembehafteten Formulars

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).

Der Bug tritt genau beim Erreichen der Höhe 0 des Detailbereichs auf.

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.

Das Formular direkt nach dem Öffnen

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

Schreibe einen Kommentar