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

Achtung: Dies ist nicht der vollständige Artikel, sondern nur ein paar Seiten davon. Wenn Sie hier nicht erfahren, was Sie wissen möchten, finden Sie am Ende Informationen darüber, wie Sie den ganzen Artikel lesen können.

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:

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 3/2005.

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

Undo in Formularen und Unterformularen

André Minhorst, Duisburg

Die Verwendung von Formularen und Unterformularen ist ein probates Mittel zur Darstellung von Daten aus 1:n- und m:n-Beziehungen. Dabei tritt immer wieder das Ärgernis zu Tage, dass Access von Haus aus keine Möglichkeit mitbringt, Änderungen an den Daten im Unterformular in einem Schritt mit denen des Hauptformulars rückgängig zu machen. Dieser Beitrag stellt eine Lösung vor, wie die Benutzer einer Datenbank dennoch mit einem Mausklick komplexe Änderungen rückgängig machen können.

Hinweis

Die Beispieldatenbanken zu diesem Beitrag heißen Forms.mdb und FormsAndSubforms.mdb. Sie finden die Datenbanken auf der Heft-CD oder im Internet unter http://www.access-im-unternehmen.de unter dem Shortlink 276. Nützliche Informationen gibt es im Beitrag Transaktionen in Access, Shortlink 275. (

Das Dilemma

Der Einsatz von Haupt- und Unterformularen ist durch die Verknüpfung der Datenherkünfte dieser beiden sehr hilfreich, ermöglicht er doch die Bearbeitung zusammenhängender Daten wie beispielsweise Bestellungen und bestellter Artikel (s. Abb. 1).

Abb. 1: Anzeige von Bestelldaten in Haupt- und Unterformular

Leider lassen diese Formulare eine sehr wichtige Eigenschaft vermissen: Sie bieten keine Undo-Funktion, die alle seit dem Anzeigen des Datensatzes im Hauptformular getätigten Änderungen rückgängig macht. Es reicht gerade zu einer Undo-Funktion für den im Hauptformular angezeigten Datensatz. Wenn man einmal versehentlich den Hauptformular-Datensatz wechselt und Änderungen an den Datensätzen im Unterformular vornimmt, ist dort maximal der letzte bearbeitete Datensatz noch zu retten. Den Rest können Sie aus dem Gedächtnis reproduzieren.

Die Lösung

Wenn Sie nicht aus Sicherheitsgründen vor jeder Verwendung solcher Formulare eine Kopie der Datenbank anlegen möchten, lesen Sie weiter: Zum Warmmachen erfahren Sie zunächst, wie Sie Änderungen in einem einfachen Formular vom Öffnen des Formulars an verwerfen können, und dann geht es an die Unterformulare: Hier lernen Sie, wie Sie alle Änderungen am aktuellen Datensatz des Hauptformulars und den verknüpften Datensätzen des Unterformulars mit einem Mausklick rückgängig machen - wenn Sie den Datensatz nicht zwischenzeitlich verlassen oder gespeichert haben.

Abhilfe schafft die Verwendung so genannter Transaktionen, mit denen man eine Abfolge von Datenbankaktionen zusammenfassen und entweder komplett übernehmen oder wieder verwerfen kann.

Hinweis

Der Beitrag Transaktionen in Access in der vorliegenden Ausgabe von Access im Unternehmen (oder unter http://www.access-im-unternehmen.de, Shortlink 275) beschreibt im Detail, wie Transaktionen funktionieren und wie man sie einsetzen kann. (

Die wichtigsten Merkmale von Transaktionen in diesem Zusammenhang sind die, dass alle innerhalb einer Transaktion zu berücksichtigenden Vorgänge im Kontext eines Workspace-Objekts (DAO) oder eines Connection-Objekts (ADO) erfolgen müssen und dass alle auf diese Weise durchgeführten Änderungen entweder komplett zu speichern oder komplett zu verwerfen sind.

Beispieldatenbank

Die Beispieldatenbanken enthalten zwei sehr einfach aufgebaute Tabellen. Die erste heißt tblKunden und enthält neben dem Primärschlüsselfeld KundeID lediglich das Feld Kundenname. Die zweite Tabelle heißt tblProjekte und besteht aus den Feldern ProjektID, Projekt und KundeID. Letzteres ist ein Fremdschlüsselfeld für die Verknüpfung mit der Tabelle tblKunden.

Hinweis

Die hier vorgestellten Techniken funktionieren nur unter Access 2000 und höher. (

Undo in einfachen Formularen

Bereits bei der Arbeit mit einem Formular kann es sinnvoll sein, alle seit dem Öffnen des Formulars durchgeführten Änderungen wieder rückgängig zu machen. Wie das funktioniert, erfahren Sie in nachfolgendem Beispiel.

Das hier verwendete Formular basiert auf der Tabelle tblKunden und zeigt lediglich die beiden Felder dieser Tabelle an (s. Abb. 2). Zusätzlich enthält das Formular eine Schaltfläche namens cmdOK und eine namens cmdAbbrechen.

Letztere soll dafür sorgen, dass alle seit dem Öffnen des Formulars durchgeführten Änderungen verworfen werden.

Bis Access 2000 gab es keine Möglichkeit, die während der Arbeit mit einem Formular ablaufenden Aktionen in einer Transaktion zusammenzufassen. Der Grund sind die bereits weiter oben beschriebenen Workspace- beziehungsweise Connection-Objekte, in deren Kontext die Transaktion abläuft. Gebundene Formulare arbeiten Datenoperationen außerhalb der üblichen Bereiche ab, sodass sich dort keine Transaktion starten lässt.

Abb. 2: Beispielformular für das formularweite Undo

Der Unterschied ab Version 2000, der dies erlaubt, ist die Möglichkeit der Verwendung von Recordset-Objekten als Datenherkunft von Formularen.

Das Beispielformular ist derzeit noch an die Tabelle tblKunden gebunden, da Sie diese Tabelle als Datenherkunft des Formulars festgelegt haben.

Ab Access 2000 können Sie das Formular auch an ein Recordset-Objekt binden, das die Daten dieser Tabelle enthält.

Um das nachzuvollziehen, leeren Sie einfach die Eigenschaft Datenherkunft des Formulars und legen für die Ereigniseigenschaft die Prozedur aus Quellcode 1 an.

Private Sub Form_Open(Cancel As Integer)

    Dim db As DAO.Database

    Dim rst As DAO.Recordset

    Set db = CurrentDb

    Set rst = db.OpenRecordset _
        ("tblKunden", dbOpenDynaset)

    Set Me.Recordset = rst

End Sub

Quellcode 1

Wenn Sie das Formular erneut öffnen, stellen Sie fest, dass es wie vorher die gewünschten Daten anzeigt.

Private Sub Form_Delete(Cancel As Integer)

    If bolDirty = False Then

        bolDirty = True

        DBEngine.BeginTrans

    End If

End Sub

Private Sub Form_Dirty(Cancel As Integer)

    If bolDirty = False Then

        bolDirty = True

        DBEngine.BeginTrans

    End If

End Sub

Quellcode 2

Private Sub cmdOK_Click()

    DoCmd.RunCommand acCmdSaveRecord

    If bolDirty = True Then

        DBEngine.CommitTrans

    End If

    DoCmd.Close acForm, Me.Name

End Sub

Quellcode 3

Private Sub cmdAbbrechen_Click()

    If bolDirty = True Then

        DBEngine.Rollback

    End If

    DoCmd.Close acForm, Me.Name

End Sub

Quellcode 4

Es gibt zwei Ereignisse, die beim Ändern oder Löschen von Daten ausgelöst werden: Bei Geändert und Beim Löschen. Das Ereignis, das als Erstes ausgelöst wird, muss die Transaktion starten. Damit bei mehreren Änderungen am Datenbestand nicht jedes Mal eine neue Transaktion gestartet wird, fragt die jeweilige Ereignisprozedur nach, ob schon eine Transaktion gestartet wurde. Für diesen Zweck legen Sie eine Variable namens bolDirty im Kopf des Moduls an:

Dim bolDirty As Boolean

Mit dieser Variable im Gepäck können Sie direkt die Prozeduren anlegen, die durch die Ereigniseigenschaften Bei Geändert und Beim Löschen ausgelöst werden (s. Quellcode 2). Die Prozeduren prüfen, ob die Variable bolDirty den Wert False hat, und starten in diesem Fall eine Transaktion.

Schließlich legen Sie für die Schaltflächen cmdOK und cmdAbbrechen noch zwei Prozeduren an, die prüfen, ob eine Transaktion begonnen wurde, und diese gegebenenfalls beenden oder abbrechen.

Die OK-Schaltfläche löst die Prozedur aus Quellcode 3 aus. Da der Benutzer diese Schaltfläche möglicherweise anklickt, obwohl der aktuelle Datensatz zwar bearbeitet, aber noch nicht gespeichert ist, speichert die Prozedur den Datensatz zunächst. Anschließend prüft die Prozedur den Wert der Variablen bolDirty und damit, ob eine Änderung durchgeführt und eine Transaktion ausgelöst wurde. Ist das der Fall, wird das Speichern der innerhalb der Transaktion durchgeführten Änderungen ausgelöst.

Die Abbrechen-Schaltfläche soll alle Änderungen, die seit dem Öffnen des Formulars durchgeführt wurden, rückgängig machen.

Dies ist nur nötig, wenn entweder Änderungen gespeichert wurden oder dies nicht der Fall ist und es offene Änderungen gibt. In beiden Fällen sorgt die Rollback-Methode für das Verwerfen der vorgenommenen Änderungen (s. Quellcode 4).

Probieren Sie das Formular nun aus. Wenn Sie etwa den Namen eines Kunden ändern und anschließend auf OK klicken, wird diese Änderung gespeichert und beim nächsten Öffnen wieder angezeigt. Klicken Sie auf Abbrechen und öffnen das Formular erneut, finden Sie den Datensatz unverändert vor.

Interessant wird es aber erst bei mehreren Änderungen: Löschen Sie einen Datensatz, fügen Sie einen neuen hinzu und ändern Sie vorhandene Datensätze - mit einem Klick auf die Abbrechen-Schaltfläche und dem erneuten Öffnen des Formulars finden Sie den alten Stand wieder vor.

Transaktionen in Haupt- und Unterformular

Genauso nützlich wie das Verwerfen von Änderungen mehrerer Datensätze in einem Formular ohne Unterformular ist die Vorgehensweise in Formularen mit Unterformular. Dabei kommt größtenteils die bereits beschriebene Technik zum Zuge, allerdings lässt sich die Lösung nur auf einen einzelnen Datensatz im Hauptformular und die verknüpften Datensätze im Unterformular ausführen.

Der Grund ist, dass wie bei dem vorherigen Beispiel eine Transaktion nur Datenbankoperationen innerhalb des angegebenen - in diesem Fall des aktuellen - Workspace berücksichtigen kann. Wie beim Hauptformular klappt dies auch in Unterformularen nur, wenn die Datenherkunft mittels Recordset-Objekt zugewiesen wird. Die Zuweisung muss bei jedem Datensatzwechsel im Hauptformular erneut durchgeführt werden.

Leider lässt sich der Recordset-Eigenschaft kein entsprechendes Objekt zuweisen, während eine Transaktion läuft. Daher müssen Sie auf den kompletten Komfort - also Änderungen in mehreren Hauptformulardatensätzen plus den im Unterformular angezeigten Daten rückgängig zu machen - leider verzichten und mit dem Verwerfen der Änderungen des aktuellen Datensatzes im Hauptformular und der verknüpften Daten im Unterformular vorlieb nehmen.

In einem Formular wie dem Bestellformular aus Abb. 1 könnten Sie also nach Lust und Laune Änderungen vornehmen und bestellte Artikel hinzufügen und wieder entfernen - nach einem Klick auf eine (hier nicht vorhandene) Abbrechen-Schaltfläche wäre alles wieder beim Alten.

Voraussetzungen

Für die Funktion der nachfolgend beschriebenen Technik müssen einige Voraussetzungen erfüllt sein:

  • Haupt- und Unterformular sind nicht gebunden, die Steuerelemente enthalten aber als Steuerelementinhalt die Felder der später hinzugefügten Datenherkunft.
  • Die Anzeige der Bestätigungen von Datensatzänderungen ist aktiviert (Dialog Optionen, Registerblatt Bearbeiten/Suchen). Sonst wird das Ereignis Nach Löschbestätigung nicht ausgelöst, ohne die die Lösung nicht funktioniert.
  • Aufbau der Formulare

    Das Hauptformular ist genauso wie das Formular aus dem vorherigen Beispiel aufgebaut. Erstellen Sie es zu Beispielzwecken neu oder kopieren Sie das vorhandene Formular und entfernen Sie den enthaltenen Code.

    Das Unterformular sieht im Entwurf wie in
    Abb. 3 aus. Zum Erstellen des Formulars stellen Sie zunächst die Datenherkunft auf die Tabelle tblKunden ein, ziehen alle Felder aus der Feldliste in den Detailbereich und löschen dann den für die Eigenschaft Datenherkunft angegebenen Wert - die Datenherkunft wird später dynamisch zugewiesen. Ordnen Sie die Steuerelemente wie in der Abbildung an.

    Abb. 3: Entwurfsansicht des Unterformulars

    Option Compare Database

    Option Explicit

    Dim mDirtyForm As Boolean

    Dim mDeletedForm As Boolean

    Dim db As DAO.Database

    Dim wrk As DAO.Workspace

    Public Property Get DirtyForm() As Boolean

        DirtyForm = mDirtyForm

    End Property

    Public Property Let DirtyForm (bolDirtyForm As Boolean)

        mDirtyForm = bolDirtyForm

    End Property

    Quellcode 5

    Private Sub Form_Open(Cancel As Integer)

        Dim rst As DAO.Recordset

        Set db = DBEngine(0)(0)

        Set wrk = DBEngine.Workspaces(0)

        Set rst = db.OpenRecordset("tblKunden", _
            dbOpenDynaset)

        Set Me.Recordset = rst

    End Sub

    Quellcode 6

    Abb. 4: Haupt- und Unterformular in der Entwurfsansicht

    Fügen Sie nun das Formular frmProjekte als Unterformular in das Formular frmKundenProjekte ein (s. Abb. 4).

    VBA-Code der
    Formulare

    Die Funktionalität des Formulars aus dem ersten Beispiel muss nun angepasst und auf das Unterformular ausgedehnt werden. Das bedeutet, dass Transaktionen nicht mehr nur aus dem Hauptformular, sondern auch aus dem Unterformular heraus gestartet werden können. Dementsprechend müssen auch die Variablen zum Speichern der Zustände (bolDirtyForm und bolSavedForm) in beiden Formularen verfügbar sein.

    Eine öffentliche Deklaration ist nicht besonders vorteilhaft, daher verwenden Sie Property Get- und Property Set-Anweisungen für den Zugriff auf diese Variablen. Deren Deklaration erfolgt nach wie vor im Codemodul des Hauptformulars. Der erste Teil des Moduls enthält die in Quellcode 5 abgebildeten Zeilen.

    Öffnen des
    Hauptformulars

    Das Öffnen des Hauptformulars löst die Ereignisprozedur Form_Open aus. Die Prozedur stellt die Variablen db und wrk auf das aktuelle Database- und Workspace-Objekt ein und weist der Recordset-Eigenschaft des Formulars ein Recordset-Objekt mit der Tabelle tblKunden zu (s. Quellcode 6).

    Anzeigen eines neuen
    Datensatzes

    Private Sub Form_Current()

        Dim rst As DAO.Recordset

        If Me.DirtyForm = True Then

            DoCmd.RunCommand acCmdSaveRecord

            wrk.CommitTrans

            Me.DirtyForm = False

        End If

        If mDeletedForm = False Then

            UnterformularAktualisieren

        Else

            mDeletedForm = False

        End If

    End Sub

    Quellcode 7

    Private Sub Form_Dirty(Cancel As Integer)

        If Me.DirtyForm = False Then

            Me.DirtyForm = True

            wrk.BeginTrans

        End If

    End Sub

    Quellcode 8

    Private Sub Form_Delete(Cancel As Integer)

        mDeletedForm = True

    End Sub

    Quellcode 9

    Private Sub Form_AfterDelConfirm(Status As Integer)

        UnterformularAktualisieren

    End Sub

    Quellcode 10

    Das Ereignis Beim Anzeigen wird nach dem Öffnen des Formulars und bei jedem Datensatzwechsel ausgelöst.

    Damit tritt die entsprechende Prozedur vor allem immer dann in Aktion, wenn der Benutzer einen Datensatz verlässt und einen neuen anzeigt. Das ist Grund genug, den aktuellen Datensatz und die verknüpften Daten zu speichern und eine eventuell aktive Transaktion zu beenden.

    Die Prozedur Form_Current tut dies, indem sie zunächst den Datensatz speichert, die Transaktion beendet und die Eigenschaft DirtyForm auf den Wert False zurücksetzt.

    Außerdem stellt die Prozedur die Datenherkunft des Unterformulars so ein, dass die zu dem im Hauptformular angezeigten Kunden passenden Projekte angezeigt werden (s. Quellcode 7).

    Dies passiert allerdings nur, wenn die Variable mDeletedForm den Wert True hat - wann das der Fall ist, erfahren Sie direkt im Anschluss.

    Das Ereignis Bei Änderung sorgt wie im vorherigen Beispiel dafür, dass die Eigenschaft DirtyForm auf den Wert True gesetzt und die Transaktion gestartet wird (s. Quellcode 8).

    Sie haben das Ende des frei verfügbaren Teils des Artikels erreicht. Lesen Sie weiter, um zu erfahren, wie Sie den vollständigen Artikel lesen und auf viele hundert weitere Artikel zugreifen können.

    Sind Sie Abonnent?Jetzt einloggen ...
     

    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:

    Verwandte Beiträge:

    Formularposition speichern und wiederherstellen

    Unterformulare: Daten anlegen und löschen

    Modale Dialoge mal anders

    Transparenz und andere Effekte in Formularen

    © 2003-2015 André Minhorst Alle Rechte vorbehalten.