Office Forum
www.Office-Loesung.de
Access :: Excel :: Outlook :: PowerPoint :: Word :: Office :: Wieder Online ---> provisorisches Office Forum <-
"Split Form"/Formularsynchronisation mit Events
zurück: DB mit mehrsprachigen Formularen weiter: Flyout-Menü mit Bordmitteln Unbeantwortete Beiträge anzeigen
Neues Thema eröffnen   Neue Antwort erstellen     Status: Tutorial Facebook-Likes Diese Seite Freunden empfehlen
Zu Browser-Favoriten hinzufügen
Autor Nachricht
Bitsqueezer
Office-VBA-Programmierer


Verfasst am:
22. Feb 2010, 18:49
Rufname:

"Split Form"/Formularsynchronisation mit Events - "Split Form"/Formularsynchronisation mit Events

Nach oben
       Version: (keine Angabe möglich)

Hallo zusammen,

nachdem ich nun eine Weile erfolglos versucht habe, die Split Form in Access 2007 unter Kontrolle zu bekommen, habe ich nun eine eigene Lösung erstellt.

Die Split Form an sich ist eine feine Sache, aber sie hat ein paar böse Nachteile.
  • Access verwendet intern tatsächlich zwei getrennte Formulare, um ein Formular mit der Einstellung "Split Form" darzustellen - eins für die Einzelansicht, ein weiteres für die Datasheet View. Darüber bin ich gestolpert, als ich versucht habe, eine Objektvariable in einem Formular zu speichern und im Formular darauf zuzugreifen. Mit Debug.Print bin ich nach vielen haareraufenden Tests darauf gekommen, daß das Objekt zweimal instantiiert wird beim Öffnen des Formulars, einmal für die Einzel- und einmal für die Datenblattansicht. Jetzt wäre es allerdings zu einfach, wenn MS uns geplagten Programmierern eine einfache Zugriffsmöglichkeit auf beide Formulare gegeben hätte. Tatsächlich ist es offenbar nur möglich, auf das interne zweite Formular mit "Screen.ActiveDatasheet.Form" zuzugreifen - und das funktioniert leider nicht zuverlässig.

  • ein anderer nerviger Punkt ist das automatische Erstellen von Subdatasheets. Sobald man im Formular ein gebundenes Unterformular erstellt hat, erscheint vor jeder Zeile in der Datenblattansicht ein [+], mit dem man das Unterformular zu jedem Datensatz aufklappen kann. Das ist manchmal ganz praktisch, aber je nach Unterformular auch manchmal unerwünscht. Abschalten läßt sich dieses Feature offenbar ebenfalls nicht. Hat man mehr als ein Unterformular, so ist dasjenige mit der früheren Tab-Einstellung das verbundene Formular.

  • dieses Feature hat (zumindest bei mir) offenbar auch noch einen fetten Bug: Hat man ein UFO eingebunden und ändert per VBA das SourceObject, dann wird das neue UFO im Einzelformular sofort und richtig angezeigt. Da das Datenblattformular aber ein getrenntes Formular ist, ändert sich dort nichts. Dafür hängt sich Access komplett auf, sobald man versucht, mit [+] ein Unterformular in der Datenblattansicht aufzuklappen.
Neue Features sind ja was feines, aber ein bißchen mehr Nachdenken hätte ich schon erwartet. So ist die Split Form eigentlich nur für Formulare geeignet, die nur Standardfunktionen verwenden und die auch keine Unterformulare verwenden, wenn man das [+] nicht haben will. Daß man auf das zweite Formular sozusagen gar nicht zugreifen kann, halte ich auch für einen fetten Bug.

Da ich in meiner gegenwärtigen Anwendung aber sowohl intensiven Objektgebrauch mache als auch Unterformulare verwende, habe ich nun ein anderes schönes Feature von Access hervorgeholt, das sehr selten gebraucht wird und sehr schlecht dokumentiert ist: Die Events.

Events sind an sich etwas sehr bekanntes und geläufiges, wohl jeder hat sie schon in Zusammenhang mit Formularen angewendet, um zum Beispiel BeimLaden etwas mit dem Formular zu machen.

Weniger bekannt ist, daß man Events auch selbst erstellen und verwenden kann und die Hilfe in Access bietet auch nur sehr bescheidene Beispiele. Dort wird ein Event anhand eines Timers gezeigt, die Eventklasse wird aber im Formular instantiiert und steht damit auch nur diesem Formular zur Verfügung. Macht nicht wirklich viel Sinn, zumal es einen TimerEvent in jedem Formular gibt.

In meinem gegenwärtigen Projekt habe ich es mit einer Reihe von Tabellen zu tun, die über verschiedenste Haupt- und Unterformulare angezeigt und bearbeitet werden können. Wenn in einem Formular eine Änderung stattfindet, soll die Änderung in allen Formularen stattfinden, die diese Daten derzeit ebenfalls anzeigen.
Bisher habe ich das so gelöst, daß ich den diversen Formularen eine öffentliche Methode "updateForm" verpaßt habe und dann in dem Formular, daß die Änderung weiterreichen möchte, eine Sub aufrufe, die erst testet, ob das betreffende andere Formular überhaupt geladen ist und dann dort die "updateForm"-Methode aufruft, die ja in jedem Formular sehr unterschiedlich sein kann, je nach Komplexität.

Das ist bei wenigen Formularen eine praktische Methode, aber mit zunehmender Anzahl Formulare hat das den Nachteil, daß die Tests, ob ein Formular geöffnet ist, immer langwieriger werden, da man hierzu im Regelfall die ganze Forms-Auflistung durchlaufen muß. Außerdem muß man jedes andere Formular in jedem Formular mit aufführen, das eine Änderung durchführt, und das auch noch gegenseitig.

Hier ist die beste Lösung ein Event. Die Idee ist, eine Instanz zu haben, die bestimmte Events auslöst, und auf der anderen Seite in jedem Formular einen Empfänger, der diese Events auswertet und entsprechend reagiert.

Anders ausgedrückt, wenn ein Formular einen Datensatz ändert, soll es "in die Welt" hinausrufen: "Hallo an alle, ich habe etwas geändert, wer immer zuhört, bitte aktualisieren!"

Die anderen Formulare horchen darauf und wenn etwas dabei ist, was sie betrifft, sollen sie sich aktualisieren. Vorteil: Das Formular, das "in die Welt hinausruft", muß nicht mehr wissen, ob ein anderes Formular vorhanden ist oder ob es sich wirklich um eine Aktualisierung kümmert, es gibt einfach einen Status bekannt und überläßt es den anderen, darauf zu reagieren.

Die anderen Formulare reagieren damit auch nur noch, wenn sie geladen sind, denn wenn sie nicht geladen sind, gibt es auch keine Objektvariable mehr, die darauf horchen könnte.

Das ganze funktioniert mit den drei Befehlen "Event", "WithEvents" und "RaiseEvent".

Auch hier gibt es natürlich mal wieder Haken und Ösen, wie man das von Access ja gewohnt ist...
  • ein Event kann nur in einem Klassenmodul definiert werden
  • RaiseEvent kann nur im gleichen Klassenobjekt ausgeführt werden, in dem auch dieser Event definiert ist
  • WithEvents geht ebenfalls nur in einem Klassenmodul
Zum Glück sind Formulare (und natürlich auch Reporte) in Wirklichkeit Klassenmodule und damit kann man ihnen ein "WithEvents" Objekt verpassen. In den diversen Beispielen, die man zu dem Thema findet, wird im Regelfall immer ein Eventobjekt im FormLoad mit New erstellt, was aber in meinen Augen nahezu nie einen Sinn macht.
Denn zum Glück gibt es ja auch noch Module, und diese wiederum können globale Variablen beinhalten, wenn man sie mit "New" deklariert, kann man sie sogar gleich beim Starten der Anwendung instantiieren.

Damit haben wir alles zusammen, was für einen Nachrichtensender/-empfänger notwendig ist.

1. Der Nachrichtensender

Dieser wird einfach als globale Objektvariable in einem Modul definiert, es genügt eine einzige Zeile:
Code:
Public e As New clsEvent
Beim Starten wird damit die Klasse "clsEvent" als neues globales Objekt instantiiert und steht damit in der gesamten Anwendung zur Verfügung.

Auch die "Innereien" des Nachrichtensenders, der Klasse "clsEvent" sind sehr simpel: Man benötigt für jeden Event, den der Sender in die Welt schicken soll, eine Eventdefinition, hier mal am Beispiel eines Events für Formularsynchronisation:
Code:
Public Event syncForm(lngID As Long, strName As String)
Das ist schon alles. Die Parameter "lngID" und "strName" sind eigene Parameter, prinzipiell kann ein Event auch ohne Parameter erstellt werden.

Jetzt braucht es noch eine Möglichkeit, den Event auch auszulösen. Dummerweise (siehe Haken und Ösen) kann ein Event nur in der gleichen Klasse ausgelöst werden, die den Event definiert. Also muß man sich einfach mit einer öffentlichen Methode behelfen, so daß man die Events auch von außen starten kann.

Das erledigt für dieses Beispiel die ebenso simple Sub:
Code:
Public Sub RaiseEvtSync(lngID As Long, strName As String)
    RaiseEvent syncForm(lngID, strName)
End Sub
Damit kann man von außen die Parameter an die Eventklasse übergeben, diese löst dann den Event mit den gleichen Parametern aus, der Nachrichtensender sendet nun.

2. Der Nachrichtenempfänger

Nachrichten zu senden, denen niemand zuhört, macht nicht viel Sinn, also müssen nun die "Zuhörer" ran.

Hier kommt nun der dritte Teil der Events ins Spiel, das "WithEvents".

Ein Formular, das als Zuhörer dienen soll, kann nun sein "Radio" so installieren:
Code:
Private WithEvents evt As clsEvent
"evt" kann beliebig heißen und ist die formulareigene Empfangsstation des Typs "clsEvent". Nun muß die Variable aber auch noch mit Leben gefüllt werden, was am besten im FormLoad-Event passiert:
Code:
Private Sub Form_Load()
    Set evt = e
End Sub
Im Gegensatz zu den vielen Beispielen, die hier "Set evt= New clsEvent" verwenden, wird hier einfach die bereits vorhandene globale Instanz des Eventobjektes zugewiesen. Kabelradio ist online.

Jetzt kann ein Event empfangen werden, aber Radio alleine reicht noch nicht, wenn es kein Ohr gibt, das dem Radio zuhört. Das "Ohr" ist natürlich eine Event-Funktion und das ist altbekannte Technik in Access, denn die Formular-Eventfunktionen (z.B. FormLoad) sind auch nichts anderes als "Ohren".

Wenn man im VBA-Editor oben links in die Objektliste schaut, findet man dank der "WithEvents"-Zeile nun einen Eintrag "evt". Wählt man diesen aus, findet man rechts in der Liste die (in der Beispieldatenbank) definierten beiden Events. Diese braucht man nur auszuwählen, um die entsprechenden Eventfunktionen zu erstellen. Für das Sync-Beispiel hier sieht die komplette Funktion dann so aus, wenn sie mit Leben befüllt ist:
Code:
Private Sub evt_syncForm(lngID As Long, strName As String)
    If strName = "tblTest" Then
        If lngID = 0 Then
            Forms("frmMain").sfTest.SetFocus
            DoCmd.GoToRecord , , acNewRec
          Else
            GotoID Me, lngID, "ID"
        End If
    End If
End Sub
Das "Ohr" erhält über die Parameter nun die vom Sender ausgestrahlten Parameter und kann damit etwas anfangen. Im Beispiel sieht man, daß das Testformular nur dann reagiert, wenn strName="tblTest" ist. Außerdem wird im Formular zu der in lngID angegebenen ID gesprungen (das erledigt die kleine Funktion "GotoID", die im Modul "modEvent" steht) oder, falls die ID 0 ist, auf einen neuen Datensatz springt.

strName dient der weiteren "Ohrunterscheidung": Während der Eventsender einfach an alle teilnehmenden Radios hinausposaunt, das alle Feuerwehrleute aus Untertupfingen zum Dienst antreten sollen, interessieren sich die Krankenschwestern aus Neustadt überhaupt nicht dafür und sollen auch nicht darauf reagieren - was sollen auch Krankenschwestern in Untertupfingen Feuer löschen?

In unserem Fall heißt das einfach: Wenn ein bestimmter Name aus dem Radio erschallt, sollen alle Formulare reagieren, die diesen Namen abfragen. Ein String ist natürlich nur eine Möglichkeit, man kann beliebige andere Varianten verwenden, um ein Zielformular anzusprechen, bis hin zu komplexen Objekten ist beinahe jeder Datentyp erlaubt.

Wenn das Formular dann reagiert, sagt die SynchronisationsID aus, zu welcher ID der Benutzer in dem Formular gehoppelt ist, das die Nachrichtensendung ausgelöst hat.

Und da kommt der dritte Teil ins Spiel:

3. Der Nachrichtenersteller

Was hilft der schönste Radiosender, wenn es keinen Nachrichtensprecher gibt, der auch etwas zu verkünden hat?

Da kommen nun die öffentlichen Methoden ins Spiel, um eine Nachricht auszulösen. Wir haben es mit einem liberalen Nachrichtensender zu tun: Jeder kann eine Nachricht erstellen und diese wird auch sofort gesendet und garantiert nicht zensiert.

Das wird in der Beispieldatenbank genutzt, um zwei Unterformulare miteinander zu synchronisieren. Beide sind Nachrichtenersteller, Radio und Zuhörer.

Das hier verwendete Hauptformular hat gar nichts zu tun, es ist lediglich der Container für die Unterformulare.

Jedes der beiden Unterformulare verwendet die gleiche Tabelle als Datenquelle, sonst würde eine Synchronisierung ja auch nicht viel Sinn machen. Das linke Formular verwendet eine Endlosdarstellung, das rechte eine Datenblattansicht. Der beste Zeitpunkt, eine Nachricht darüber zu senden, daß zu einem neuen Datensatz gewechselt wurde, ist natürlich der FormCurrent-Event. Sobald dieser ausgelöst wird, wird eine Nachricht darüber an alle gesendet:
Code:
Private Sub Form_Current()
    e.RaiseEvtSync Nz(Me.ID, 0), "tblTest"
End Sub
Naja, nicht ganz an alle. Eben nur an die Feuerwehrleute, oder hier "tblTest". (Statt des Tabellennamens hätte es natürlich auch "Feuerwehr" sein können, der Text spielt keine Rolle. Solange jemand da ist, der auf "Feuerwehr" reagiert.)

Mit Nz wird festgestellt, ob es sich um einen neuen Datensatz handelt, in dem Fall ist die ID NULL und wird durch Nz auf 0 gesetzt, was die oben gezeigte Eventfunktion abfragt.

Nachricht ist raus, nun können alle Formulare, die dieses Radio eingebaut haben, die einen Zuhörer für diese Nachrichtenart eingerichtet haben (die Eventfunktion) und die zudem auch noch auf den Text reagieren ("tblTest") eine entsprechende Funktion ausführen, hier eben, auf den gleichen Datensatz zu springen.

Da das auch wechselseitig funktioniert, werden in beide Formulare Sender und Empfänger installiert und schon hat man eine perfekte Formularsynchronisation.

In der Beispieldatenbank ist ein weiterer Event für Formularupdates enthalten, der bei Änderung eines Datensatzes die Änderung auch sofort in jedem anderen Formular anzeigt, das die gleichen Daten anzeigt. Zu dem Zweck wird auch noch eine Synchronisationsnachricht verwendet, die nach dem Requery wieder zum richtigen Datensatz springt (kleiner Wermutstropfen dabei ist natürlich, daß bei einem Zeilenwechsel der Cursor danach wieder in der geänderten Zeile steht statt in der, in die man gewechselt hat, aber ich finde, damit kann man gut leben. Mit weiteren Events könnte man das natürlich auch behandeln.).

Das Tolle daran: Die Anzahl und Lage der Formulare ist nun völlig egal. Es kann ein UFO in einem UFO in einem UFO in einem Hauptformular sein, es kann ein getrennt geöffnetes Formular sein, es können beliebig viele Formulare sein und auch beliebig geöffnet (mit DoCmd oder als Objekt), da der Event an alle hinausgeht, die sich ein Radio aufgestellt haben, kann jeder individuell auf die Nachricht reagieren und jedes Formular "weiß" ja für gewöhnlich den Pfad, wie man auf es zugreifen kann.
Das gilt natürlich nicht nur für die Updates, sondern auch für die Synchronisation: Wenn man statt wie im Beispiel 10 Unterformulare integrieren würde, würden sich auch alle 10 synchronisieren, mit dem nahezu gleichen Code im Hintergrund.

Da die selbsterstellten Events keine Grenzen kennen, kann man im Radiosender beliebig viele installieren, mit beliebigen Parametern, die beliebige Datentypen weiterreichen können. Enstprechend läßt sich mit etwas Phantasie noch eine ganze Menge anderer Funktionen automatisieren.

Mit dieser Methode kann man auf einfache Weise eine Split Form in jeder Access Version realisieren, die Events verarbeiten kann. Die angehängte Datei sollte in den Versionen Access 2000, XP, 2003 und 2007 lauffähig (und vermutlich auch in 2010) sein.

Im Gegensatz zur echten Split Form kann man nun auf jedes Formular wie gewohnt zugreifen.

Viel Spaß beim Experimentieren

Christian



Events.zip
 Beschreibung:
Formularsynchronisation mit Events, Versionen für Access 2000-2007

Download
 Dateiname:  Events.zip
 Dateigröße:  88.83 KB
 Heruntergeladen:  252 mal

derArb
getting better


Verfasst am:
22. Feb 2010, 21:02
Rufname: derArb
Wohnort: Berlin

AW: "Split Form"/Formularsynchronisation mit Event - AW: "Split Form"/Formularsynchronisation mit Event

Nach oben
       Version: (keine Angabe möglich)

hallo,

danke Bisqueezer. Das Formularsplitten hatte ichschon ad acta gelegt.
Werde mich mit Deinen Tips gerne auseinandersetzen und dazulernen.

mfg
derArb

_________________
MfG
derArb

Scio me nihil scire...Εν οίδα οτι ουδέν οίδα... Ich weiss, dass ich nichts weiss (Sokrates)
Ich bevorzuge Beiträge mit korrekter deutscher Grammatik.
Bitsqueezer
Office-VBA-Programmierer


Verfasst am:
22. Feb 2010, 23:59
Rufname:


AW: "Split Form"/Formularsynchronisation mit Event - AW: "Split Form"/Formularsynchronisation mit Event

Nach oben
       Version: (keine Angabe möglich)

Hallo derArb,

immer gern, freue mich auch immer über Feedback und eigene Ideen.

Gruß

Christian
Neues Thema eröffnen   Neue Antwort erstellen Alle Zeiten sind
GMT + 1 Stunde

Diese Seite Freunden empfehlen

Seite 1 von 1
Gehe zu:  
Du kannst Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.
Du kannst Dateien in diesem Forum nicht posten
Du kannst Dateien in diesem Forum herunterladen

Verwandte Themen
Forum / Themen   Antworten   Autor   Aufrufe   Letzter Beitrag 
Keine neuen Beiträge Access Tabellen & Abfragen: Form basierten Filter in Tabelle ausgeben 1 der Jöns 600 02. Sep 2008, 22:21
maike kaluscha Form basierten Filter in Tabelle ausgeben
Keine neuen Beiträge Access Tabellen & Abfragen: Berechnetes Feld aus einem Form. in eine Tabelle speichern?? 1 Realhasko 402 21. Jul 2008, 16:40
rita2008 Berechnetes Feld aus einem Form. in eine Tabelle speichern??
Keine neuen Beiträge Access Formulare: Werte aus Operationen i. Form werden nicht in Tab. übern. 3 Birg 391 17. Apr 2007, 22:44
stpimi Werte aus Operationen i. Form werden nicht in Tab. übern.
Keine neuen Beiträge Access Formulare: Form durch in Tbl hinterlegte Zahlencodes absichern 5 NewFritz 398 16. Apr 2007, 21:43
NewFritz Form durch in Tbl hinterlegte Zahlencodes absichern
Keine neuen Beiträge Access Formulare: Zwei Formular Probleme (two form problems) 5 Gast123 702 05. Apr 2007, 16:17
Willi Wipp Zwei Formular Probleme (two form problems)
Keine neuen Beiträge Access Formulare: Wert aus einem Form in ein weiteres Form übergeben 6 maluk 706 24. März 2007, 01:08
valli Wert aus einem Form in ein weiteres Form übergeben
Keine neuen Beiträge Access Formulare: keine werte im form angezeigt 7 heino 503 16. Feb 2007, 19:53
heino keine werte im form angezeigt
Keine neuen Beiträge Access Formulare: Problem bei Sicherheitsabfrage und Form schliessen 3 samba 794 12. Dez 2006, 13:01
samba Problem bei Sicherheitsabfrage und Form schliessen
Keine neuen Beiträge Access Formulare: Standardwert für ein Auswahlfeld im Form per Variable setzen 6 Stefi 4541 31. Okt 2006, 23:31
derArb Standardwert für ein Auswahlfeld im Form per Variable setzen
Keine neuen Beiträge Access Formulare: Zwischenspeichern in Form ohne zu 1. Datensatz zu springen 2 Gast 802 14. Aug 2006, 14:01
Gast Zwischenspeichern in Form ohne zu 1. Datensatz zu springen
Keine neuen Beiträge Access Formulare: Grafik in Form einbinden - darin scrollen und zentrieren 1 MR-GIGG 809 18. Okt 2005, 07:51
Frank_xyz Grafik in Form einbinden - darin scrollen und zentrieren
Keine neuen Beiträge Access Formulare: DS aus Form löschen 4 DieterB 607 14. Okt 2005, 15:40
DieterB DS aus Form löschen
 

----> Diese Seite Freunden empfehlen <------ Impressum - Besuchen Sie auch: Dreamweaver Forum