{"id":55001382,"date":"2022-10-01T00:00:00","date_gmt":"2022-10-03T14:37:05","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1382"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Rechnungsverwaltung_Bestellformular","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/","title":{"rendered":"Rechnungsverwaltung: Bestellformular"},"content":{"rendered":"<p><b>Nachdem wir das Datenmodell f&uuml;r unsere Rechnungsverwaltung angelegt sowie die Tabellen mit Beispieldaten gef&uuml;llt haben, kommt als N&auml;chstes die Benutzeroberfl&auml;che zum Verwalten der Kunden-, Produkt- und Bestelldaten an die Reihe. Die dazu notwendigen Formulare stellen wir in mehreren Teilen dieser Beitragsreihe vor. Die Basis ist das Formular zum Anzeigen der Bestellungen, mit dem wir den Kunden ausw&auml;hlen, die Bestelldaten eingeben und die Bestellpositionen hinzuf&uuml;gen k&ouml;nnen. Die Programmierung dieses Formulars zeigen wir im vorliegenden Beitrag &#8211; inklusive Validierung und mehr.<\/b><\/p>\n<h2>Leichter programmieren mit Testdaten<\/h2>\n<p>Das Sch&ouml;ne ist, dass wir im Beitrag <b>Rechnungsverwaltung: Beispieldaten <\/b>(<b>www.access-im-unternehmen.de\/1381<\/b>) bereits einige Beispieldatens&auml;tze angelegt haben, sodass wir beim Programmieren der Formulare nicht immer noch m&uuml;hselig von Hand Testdaten eingeben m&uuml;ssen. Dabei sollten wir aber nicht vergessen, dass der Kunde die Anwendung gegebenenfalls ohne Daten erh&auml;lt. In diesem Fall m&uuml;ssen wir die Formulare auch noch mit leeren Tabellen testen, um zu pr&uuml;fen, ob das initiale Anlegen von Daten ebenfalls funktioniert und ob die Formulare komplett ohne Daten genauso gut funktionieren.<\/p>\n<h2>Reihenfolge beim Anlegen der Formulare<\/h2>\n<p>Wenn Sie keine Testdaten zur Verf&uuml;gung h&auml;tten, w&uuml;rden Sie die Formulare logischerweise in einer Reihenfolge erstellen, in der auch die Daten eingegeben werden. Wir w&uuml;rden also zuerst ein Formular zur Eingabe von Anreden, Einheiten und Mehrwertsteuers&auml;tzen ben&ouml;tigen, dann f&uuml;r Kunden und Produkte und schlie&szlig;lich f&uuml;r Bestellungen und Bestelldetails (wobei letztere in einem Formular plus Unterformular untergebracht werden).<\/p>\n<p>Mit Testdaten k&ouml;nnen wir das Erstellen der Formulare allerdings in beliebiger Reihenfolge gestalten. Also beginnen wir doch gleich mal mit dem aufwendigsten Formular &#8211; dem zur Eingabe der Bestellungen.<\/p>\n<h2>Formulare zur Eingabe von Bestellungen<\/h2>\n<p>Zur Eingabe von Bestellungen ben&ouml;tigen wir eigentlich nur ein einfaches Formular, aber zu Bestellungen geh&ouml;ren ja auch noch Bestellpositionen. Und da diese &uuml;ber eine 1:n-Beziehung mit den Bestellungen verkn&uuml;pft sind, bietet sich die Verwendung eines Unterformulars an.<\/p>\n<p>Wir erstellen zuerst das Hauptformular und &ouml;ffnen es in der Entwurfsansicht. Dieses nennen wir <b>frmBestellungDetails <\/b>und weisen ihm f&uuml;r die Eigenschaft <b>Datensatzquelle <\/b>die Tabelle <b>tblBestellungen <\/b>zu. Danach wechseln wir zur Feldliste und ziehen alle Felder au&szlig;er <b>ID <\/b>in den Detailbereich des Formularentwurfs (siehe Bild 1). Warum nicht das Feld <b>ID<\/b>? Weil dieses ein rein f&uuml;r die Herstellung von Beziehungen verwendetes Feld ist und der Benutzer dieses ohnehin nicht &auml;ndern kann und soll. Die Beschriftungen m&uuml;ssen wir noch ein wenig anpassen, sodass beispielsweise aus <b>KundeID <\/b>die Beschriftung <b>Kunde <\/b>wird oder aus <b>BestelltAm <\/b>die Beschriftung <b>Bestellt am<\/b>. Au&szlig;erdem fehlen &uuml;berall noch Doppelpunkte.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_001.png\" alt=\"Das Formular frmBestellungDetails in der Entwurfsansicht\" width=\"649,559\" height=\"405,6464\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Das Formular frmBestellungDetails in der Entwurfsansicht<\/span><\/b><\/p>\n<p>Diese &Auml;nderungen h&auml;tten wir auch schon zu einem fr&uuml;heren Zeitpunkt vorbereiten k&ouml;nnen, n&auml;mlich im Tabellenentwurf. Dort h&auml;tten wir diese Bezeichnungen f&uuml;r die Eigenschaft Beschriftung der jeweiligen Felder eintragen k&ouml;nnen. Da wir nicht wissen, ob wir noch weitere Formulare oder Berichte auf Basis dieser Felder erstellen, nehmen wir diese &Auml;nderungen noch schnell vor. Dazu &ouml;ffnen wir die Tabelle <b>tblBestellungen <\/b>nochmals in der Entwurfsansicht und stellen dort f&uuml;r die verschiedenen Felder die gew&uuml;nschten Beschriftungen in der gleichnamigen Eigenschaft ein (siehe Bild 2).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_002.png\" alt=\"Voreinstellung f&uuml;r die Beschriftung von Feldern, auch in Formularen oder Berichten\" width=\"599,559\" height=\"498,4646\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Voreinstellung f&uuml;r die Beschriftung von Feldern, auch in Formularen oder Berichten<\/span><\/b><\/p>\n<h2>Doppelpunkte zu Beschriftungen hinzuf&uuml;gen<\/h2>\n<p>Und auch den Doppelpunkt hinter der Beschriftung m&uuml;ssen wir nicht von Hand anlegen. Wir k&ouml;nnen dies f&uuml;r das aktuelle Formular auch so einstellen, dass jedes Feld automatisch einen Doppelpunkt erh&auml;lt. Dazu m&uuml;ssen Sie jedoch bereits vor dem Hinzuf&uuml;gen der Felder der Datensatzquelle eine bestimmte Eigenschaft einstellen.<\/p>\n<p>Klicken Sie dazu in der Entwurfsansicht des Formulars im Ribbon auf <b>Formularentwurf|Steuerelemente|Textfeld<\/b>, aber f&uuml;gen Sie kein Textfeld zum Formular hinzu. Das Eigenschaftsfeld zeigt nun einige Eigenschaften an, die nach dem Hinzuf&uuml;gen von Textfeldern nicht mehr erscheinen &#8211; zum Beispiel <b>Mit Doppelpunkt<\/b>. Diese Eigenschaft stellen Sie, falls dies noch nicht der Fall ist, auf <b>Ja <\/b>ein (siehe Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_003.png\" alt=\"Aktivieren des Doppelpunkts f&uuml;r Beschriftungsfelder\" width=\"649,559\" height=\"489,7122\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Aktivieren des Doppelpunkts f&uuml;r Beschriftungsfelder<\/span><\/b><\/p>\n<p>Anschlie&szlig;end bet&auml;tigen Sie die <b>Esc<\/b>-Taste, um die Auswahl des Textfeldes abzubrechen. Das Feld KundeID haben wir in der Tabelle als Nachschlagefeld ausgelegt. Das hei&szlig;t, dieses Feld wird beim Ziehen aus der Feldliste in den Formularentwurf als Kombinationsfeld erstellt. Da wir die &Auml;nderung zum Anzeigen des Doppelpunkts soeben nur f&uuml;r Textfelder eingestellt haben, m&uuml;ssen wir dies auch noch f&uuml;r Kombinationsfelder erledigen.<\/p>\n<p>Anschlie&szlig;end ziehen wir erneut die gew&uuml;nschten Felder aus der Feldliste in den Detailbereich des Formularentwurfs. Das Ergebnis sieht schon viel besser aus &#8211; die Beschriftungen aus dem Tabellenentwurf wurden &uuml;bernommen und auch die Doppelpunkte wurden hinzugef&uuml;gt (siehe Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_004.png\" alt=\"Bezeichnungsfelder mit Doppelpunkten\" width=\"424,5589\" height=\"291,9319\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Bezeichnungsfelder mit Doppelpunkten<\/span><\/b><\/p>\n<p>Damit sind die Arbeiten am Hauptformular vorerst erledigt. Sie k&ouml;nnen nun bereits in die Datenblattansicht wechseln und sehen dort die Testdaten zum Durchbl&auml;ttern. Hier erkennen Sie auch, dass wir die Breite des Kombinationsfeldes <b>KundeID <\/b>noch vergr&ouml;&szlig;ert haben (siehe Bild 5).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_005.png\" alt=\"Steuerelemente mit angepasster Breite\" width=\"424,5589\" height=\"321,1954\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Steuerelemente mit angepasster Breite<\/span><\/b><\/p>\n<h2>Unterformular f&uuml;r Bestellpositionen<\/h2>\n<p>Damit kommen wir zum Unterformular, das die Bestellpositionen zur jeweiligen Bestellung anzeigen soll. Dieses legen wir unter dem Namen <b>sfmBestellungDetails <\/b>an. Als Datensatzquelle f&uuml;gen wir die Tabelle <b>tblBestellpositionen <\/b>zu. Diese passen wir zuvor &auml;hnlich wie die Tabelle <b>tblBestellungen <\/b>noch an, indem wir passende Beschriftungen f&uuml;r die Felder <b>ProduktID <\/b>(<b>Produkt<\/b>), <b>Mehrwertsteuersatz <\/b>(<b>MwSt.-Satz<\/b>) und <b>EinheitID <\/b>(<b>Einheit<\/b>) einstellen.<\/p>\n<p>Danach ziehen wir alle Felder au&szlig;er <b>ID <\/b>und <b>BestellungID <\/b>in den Detailbereich des Formulars. ID ben&ouml;tigen wir nicht, weil es das Prim&auml;rschl&uuml;sselfeld der Tabelle ist und <b>BestellungID <\/b>dient nur dem Herstellen einer Beziehung zum jeweils im Hauptformular angezeigten Datensatz.<\/p>\n<p>Au&szlig;erdem stellen wir die Eigenschaft <b>Standardansicht <\/b>des Formulars auf <b>Datenblatt <\/b>ein. Die Bestellpositionen sollen im Unterformular tabellarisch dargestellt werden. Danach schlie&szlig;en wir das als Unterformular zu verwendende Formular.<\/p>\n<h2>Unterformular zum Hauptformular hinzuf&uuml;gen<\/h2>\n<p>Nun &ouml;ffnen wir wieder das Formular <b>frmBestellungDetails <\/b>in der Entwurfsansicht und f&uuml;gen das Unterformular <b>sfmBestellungDetails<\/b> zum Hauptformular hinzu, indem wir es aus dem Navigationsbereich in den Detailbereich des Hauptformulars ziehen &#8211; und es unter den dort bereits befindlichen Steuerelementen fallenlassen.<\/p>\n<p>Dort platzieren wir es wie in Bild 6 und &auml;ndern seine Beschriftung auf <b>Bestellpositionen<\/b>. F&uuml;r die bessere Bedienbarkeit nehmen wir noch weitere &Auml;nderungen vor. So stellen wir die Eigenschaften <b>Horizontaler Anker <\/b>und <b>Vertikaler Anker <\/b>des Unterformular-Steuerelements jeweils auf <b>Beide <\/b>ein.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_006.png\" alt=\"Haupt- und Unterformular\" width=\"599,559\" height=\"556,872\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Haupt- und Unterformular<\/span><\/b><\/p>\n<p>Dies &auml;ndert automatisch die entsprechenden Eigenschaften des Bezeichnungsfeldes des Unterformular-Steuerelemente, die wir wieder auf <b>Oben <\/b>beziehungsweise <b>Links <\/b>zur&uuml;ckstellen.<\/p>\n<p>Wie soll das Unterformular nun wissen, dass es nicht alle Bestellpositionen anzeigen soll, sondern nur die Bestellpositionen, die zum aktuell im Hauptformular angezeigten Datensatz geh&ouml;ren? Die notwendige Einstellung haben wir indirekt bereits getroffen, indem wir eine Beziehung zwischen den Feldern <b>BestellungID <\/b>der Tabelle <b>tblBestellpositionen <\/b>und <b>ID <\/b>der Tabelle <b>tblBestellungen <\/b>definiert haben. Access erkennt diese Beziehung beim Hinzuf&uuml;gen eines Unterformulars und tr&auml;gt die relevanten Daten direkt in die beiden Eigenschaften <b>Verkn&uuml;pfen von <\/b>und <b>Verkn&uuml;pfen nach <\/b>des Unterformular-Steuerelements ein. Das Ergebnis sieht wie in Bild 7 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_007.png\" alt=\"Herstellen der Beziehung der Daten aus Haupt- und Unterformular\" width=\"424,5589\" height=\"267,3957\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Herstellen der Beziehung der Daten aus Haupt- und Unterformular<\/span><\/b><\/p>\n<h2>Ausprobieren des Bestellungen-Formulars<\/h2>\n<p>Nun wechseln wir in die Formularansicht des Formulars <b>frmBestellungDetails<\/b> und finden das Ergebnis aus Bild 8 vor.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_008.png\" alt=\"Haupt- und Unterformular in der Formularansicht\" width=\"599,559\" height=\"469,997\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Haupt- und Unterformular in der Formularansicht<\/span><\/b><\/p>\n<p>Wenn wir durch die Datens&auml;tze des Hauptformulars navigieren, zeigt das Unterformular auch jeweils die passenden Datens&auml;tze an.<\/p>\n<p>Damit k&ouml;nnen wir nun auch einen der weiter oben erw&auml;hnten Tests durchf&uuml;hren, der das Anlegen einer neuen Bestellung betrifft. Dazu wechseln wir im Hauptformular zu einem neuen, leeren Datensatz. Dieser zeigt sowohl im Hauptformular als auch im Unterformular noch keine Daten an. Wenn wir nun den herk&ouml;mmlichen Weg gehen und zuerst die Daten der Bestellung im Hauptformular anlegen und dann &uuml;ber das Unterformular Bestellpositionen hinzuf&uuml;gen, l&auml;uft alles wie erwartet.<\/p>\n<p>Aber es kann ja auch sein, dass der Kunde anruft und direkt sagt, er m&ouml;chte Produkt X und Produkt Y erhalten und der neue Mitarbeiter tr&auml;gt erst einmal die entsprechenden Bestellpositionen ein, ohne die &uuml;brigen Bestelldaten hinzuzuf&uuml;gen.<\/p>\n<p>Dann geschieht Folgendes: Da im Hauptformular noch kein Datensatz angelegt wurde, tr&auml;gt Access in die neuen Datens&auml;tze im Unterformular mit den Bestellpositionen den Wert in das Fremdschl&uuml;sselfeld <b>BestellungID <\/b>ein, der auch gerade im damit verkn&uuml;pften Feld <b>ID <\/b>im Hauptformular enthalten ist &#8211; und dieser lautet <b>Null<\/b> (siehe Bild 9).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_010.png\" alt=\"Anlegen von Daten im Unterformular ohne Datensatz im Hauptformular\" width=\"499,5589\" height=\"307,4843\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Anlegen von Daten im Unterformular ohne Datensatz im Hauptformular<\/span><\/b><\/p>\n<p>Wir haben also ein paar Bestellpositionen ohne Zuweisung zu einer Bestellung (siehe Bild 10).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_009.png\" alt=\"Bestellpositionen ohne BestellungID\" width=\"700\" height=\"201,6645\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Bestellpositionen ohne BestellungID<\/span><\/b><\/p>\n<p>Noch schlimmer wird es, wenn der Mitarbeiter nun nach der Eingabe der Bestellpositionen die &uuml;brigen Daten der Bestellung nachtr&auml;gt. Das sieht zu Beginn noch so aus, als w&uuml;rde es funktionieren (siehe Bild 11).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_011.png\" alt=\"Eingabe der Bestelldaten nach den Bestellpositionen ...\" width=\"524,559\" height=\"341,0559\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 11: Eingabe der Bestelldaten nach den Bestellpositionen &#8230;<\/span><\/b><\/p>\n<p>Wenn der Benutzer dann allerdings zu einem anderen Datensatz wechselt und dann zum vorherigen Datensatz zur&uuml;ckkehrt, ist das Unterformular mit den Bestellpositionen pl&ouml;tzlich leer (siehe Bild 12).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_012.png\" alt=\"... f&uuml;hrt nach dem Datensatzwechsel zum Verschwinden der vermeintlich verkn&uuml;pften Daten im Unterformular \" width=\"524,559\" height=\"321,2923\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 12: &#8230; f&uuml;hrt nach dem Datensatzwechsel zum Verschwinden der vermeintlich verkn&uuml;pften Daten im Unterformular <\/span><\/b><\/p>\n<p>Was tun? Wir m&uuml;ssen irgendwie daf&uuml;r sorgen, dass der Benutzer nur Daten in das Unterformular eingeben kann, wenn der Datensatz im Hauptformular bereits angelegt wurde.<\/p>\n<h2>Daten erst ins Hauptformular eingeben<\/h2>\n<p>Um sicherzustellen, dass zuerst Daten ins Hauptformular und dann erst ins Unterformular eingegeben werden, wollen wir den Benutzer auf irgendeine Weise davon abhalten, die Daten umgekehrt einzugeben.<\/p>\n<p>Die erste Idee w&auml;re, das Unterformular einfach zu sperren, wenn der Benutzer gerade einen neuen Datensatz anlegt und versucht, in das Unterformular zu springen, bevor es einen Prim&auml;rsch&uuml;sselwert im Hauptformular gibt.<\/p>\n<p>Das k&ouml;nnen wir mit einer Ereignisprozedur erledigen, die durch das Ereignis <b>Beim Anzeigen <\/b>des Hauptformulars ausgel&ouml;st wird. Diese pr&uuml;ft mit der Eigenschaft <b>NewRecord<\/b>, ob das Formular gerade einen neuen, leeren Datensatz enth&auml;lt und stellt in diesem Fall die Eigenschaft <b>Enabled <\/b>des Unterformular-Steuerelements auf den Wert <b>False <\/b>ein, anderenfalls auf den Wert <b>True<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     <span style=\"color:blue;\">If <\/span>Me.NewRecord<span style=\"color:blue;\"> Then<\/span>\r\n         Me!sfmBestellungDetails.Enabled = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         Me!sfmBestellungDetails.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Dies k&ouml;nnen wir auch wesentlich k&uuml;rzer schreiben:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     Me!sfmBestellungDetails.Enabled = <span style=\"color:blue;\">Not<\/span> Me.NewRecord\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Was aber, wenn der Benutzer dann zum Beispiel den Kunden ausw&auml;hlt, was ja faktisch dazu f&uuml;hrt, dass das Autowertfeld <b>ID <\/b>der Tabelle <b>tblBestellungen <\/b>einen Wert erh&auml;lt und wir nun Bestellpositionen zum Unterformular hinzuf&uuml;gen k&ouml;nnten? Dann w&auml;re das Unterformular immer noch gesperrt, weil die obigen Prozedur nur feuert, wenn ein Datensatz angezeigt wird. Aber auch das &Auml;ndern eines neuen Datensatzes l&ouml;st ein Ereignis aus, n&auml;mlich <b>Bei Ge&auml;ndert<\/b>. F&uuml;r dieses Ereignis hinterlegen wir die folgende Prozedur, die das Unterformular aktiviert:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Dirty(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     Me!sfmBestellungDetails.Enabled = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Somit kann der Benutzer nun auch Daten in das Unterformular eingeben.<\/p>\n<p>Benutzer sind allerdings einfallsreich und die n&auml;chste Schwachstelle, die sie finden k&ouml;nnten, ist Folgende: Wenn man n&auml;mlich den Datensatz im Hauptformular &#8222;dirty&#8220; macht und dann die <b>Esc<\/b>-Taste bet&auml;tigt, werden die &Auml;nderungen wieder zur&uuml;ckgekommen und wir haben wieder einen unbefleckten Bestelldatensatz ohne <b>ID<\/b>. Das Anlegen von Bestellpositionen im Unterformular ist allerdings aktuell m&ouml;glich und w&uuml;rde zu den oben beschriebenen Problemen f&uuml;hren.<\/p>\n<p><!--30percent--><\/p>\n<p>Um dies zu verhindern, greifen wir das n&auml;chste spannende Ereignis ab, n&auml;mlich <b>Bei R&uuml;ckg&auml;ngig<\/b>. Dieses wird ausgel&ouml;st, wenn der Benutzer beispielsweise mit der <b>Esc<\/b>-Taste die bereits vorgenommen &Auml;nderungen verwirft. Hier deaktivieren wir einfach wieder das Unterformular, sofern sich im Hauptformular wieder ein neuer, leerer Datensatz befindet:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Undo(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     Me!sfmBestellungDetails.Enabled = <span style=\"color:blue;\">Not<\/span> Me.NewRecord\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Damit kann der Benutzer nun zumindest keine nicht verkn&uuml;pften Bestellpositionen mehr anlegen.<\/p>\n<h2>Bezeichnungen der Steuerelemente anpassen<\/h2>\n<p>Bevor wir gleich mit weiteren VBA-Prozeduren fortfahren, in denen wir unter anderem auf die Inhalte von Steuerelementen zugreifen wollen, legen wir f&uuml;r diese zun&auml;chst sinnvolle Namen mit Pr&auml;fix fest. Das hei&szlig;t, Textfelder erhalten das Pr&auml;fix <b>txt<\/b>, Kombinationsfelder das Pr&auml;fix <b>cbo <\/b>und so weiter.<\/p>\n<p>Dies sollten Sie zumindest f&uuml;r solche Steuerelemente durchf&uuml;hren, auf die Sie per VBA zugreifen. Auf diese Weise unterscheiden Sie die Steuerelemente von den gleichnamigen, an das Formular gebundenen Felder der Datensatzquelle.<\/p>\n<p>In Bild 13 sehen Sie, wie wir den Namen f&uuml;r das Kombinationsfeld eingestellt haben, das an das Feld <b>KundeID <\/b>gebunden ist.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_013.png\" alt=\"Einstellen von Pr&auml;fixen f&uuml;r die Steuerelementnamen\" width=\"624,559\" height=\"311,8055\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 13: Einstellen von Pr&auml;fixen f&uuml;r die Steuerelementnamen<\/span><\/b><\/p>\n<h2>Validierung<\/h2>\n<p>Wir wollen sicherstellen, dass wichtige Felder gef&uuml;llt werden. Also f&uuml;gen wir eine Prozedur hinzu, die vor dem Speichern eines Datensatzes pr&uuml;ft, ob alle notwendigen Daten angegeben wurden. Im Falle des Hauptformulars handelt es sich um die Felder <b>Bestellnummer<\/b>, <b>KundeID <\/b>und <b>BestelltAm<\/b>.<\/p>\n<p>Als Ereignis w&auml;hlen wir hierf&uuml;r das Ereignis <b>Vor Aktualisierung <\/b>des Hauptformulars aus. Dieses wird immer ausgel&ouml;st, wenn der Benutzer &Auml;nderungen an einem vorhandenen oder neuen Datensatz vorgenommen hat und die &Auml;nderungen speichert, indem er den Datensatz wechselt, das Formular schlie&szlig;t oder auch den Datensatz gezielt beispielsweise mit der Tastenkombination <b>Strg + S <\/b>speichert.<\/p>\n<p>Es gibt noch ein &auml;hnliches Ereignis namens <b>Nach Aktualisierung<\/b>, das direkt nach <b>Vor Aktualisierung <\/b>ausgel&ouml;st wird &#8211; aber in diesem sind die &Auml;nderungen bereits gespeichert. Die durch das Ereignis <b>Vor Aktualisierung <\/b>ausgel&ouml;ste Ereignisprozedur hat au&szlig;erdem den praktischen Vorteil, dass es einen Parameter namens <b>Cancel <\/b>mitbringt, den man auf <b>True <\/b>einstellen und so mit das Speichern des Datensatzes abbrechen kann.<\/p>\n<p>Also f&uuml;gen wir f&uuml;r das Ereignis <b>Vor Aktualisierung <\/b>die Prozedur aus Listing 1 hinzu. Diese pr&uuml;ft zun&auml;chst, ob das Steuerelement <b>txtBestellnummer <\/b>leer ist. Falls ja, gibt es eine Meldung aus, setzt den Fokus auf dieses Steuerelement, stellt den Parameter <b>Cancel <\/b>auf <b>True <\/b>ein und bricht die Prozedur ab (siehe Bild 14).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_014.png\" alt=\"Anzeige einer Validierungsmeldung\" width=\"624,559\" height=\"307,8253\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 14: Anzeige einer Validierungsmeldung<\/span><\/b><\/p>\n<p>Das Gleiche erledigen die beiden folgenden <b>If&#8230;Then<\/b>-Bl&ouml;cke f&uuml;r die Steuerelemente <b>cboKundeID <\/b>und <b>txtBestelltAm<\/b>. Erst wenn alle drei Felder gef&uuml;llt sind, kann der Datensatz gespeichert werden.<\/p>\n<h2>Validierung f&uuml;r einzelne Steuerelemente<\/h2>\n<p>Zumindest f&uuml;r die Datumsfelder ben&ouml;tigen wir noch individuelle Validierungen, die direkt nach der Eingabe in diese Steuerelemente ausgel&ouml;st werden m&uuml;ssen. Wenn der Benutzer hier ein ung&uuml;ltiges Datum eingibt (zum Beispiel <b>30.2.2022<\/b>) oder einen Wert, der aus anderen Gr&uuml;nden nicht als Datum erkannt werden kann, erscheint ohne weiteres Zutun die Meldung aus Bild 15.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_015.png\" alt=\"Eingebaute Meldung bei Eingabe von Text in ein Datumsfeld\" width=\"700\" height=\"212,0545\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 15: Eingebaute Meldung bei Eingabe von Text in ein Datumsfeld<\/span><\/b><\/p>\n<p>Diese Meldung wollen wir unbedingt durch eine eigene Meldung ersetzen. Normalerweise sollte man annehmen, dass wir dies mit der Prozedur erledigen k&ouml;nnen, die wir f&uuml;r die Ereigniseigenschaft <b>Vor Aktualisierung <\/b>des jeweiligen Textfeldes anlegen. Dieses Ereignis gibt es f&uuml;r das Formular selbst und auch f&uuml;r verschiedene Steuerelemente. F&uuml;r das Textfeld <b>txtBestelltAm <\/b>hinterlegen wir beispielsweise die Ereignisprozedur aus Listing 2. Diese funktioniert aber nicht &#8211; wir erhalten immer noch die Meldung aus der Abbildung.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>txtBestelltAm_BeforeUpdate(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> IsDate(Me!txtBestellnummer)<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie ein g&uuml;ltiges Bestelldatum ein.\", vbOKOnly + vbExclamation, \"Bestelldatum ist ung&uuml;ltig\"\r\n         Me!txtBestelltAm.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Validierung eines Datumsfeldes<\/span><\/b><\/p>\n<p>Das Grund ist, dass Verletzungen von Restriktionen wie Eingabe ung&uuml;ltiger Werte f&uuml;r Datentypen einen Formularfehler ausl&ouml;sen, bevor das Ereignis <b>Vor Aktualisierung <\/b>des Formulars ausgel&ouml;st wird. Also m&uuml;ssen wir ein anderes Ereignis f&uuml;r diese Validierung nutzen.<\/p>\n<h2>Validieren mit Formularfehler<\/h2>\n<p>Es gibt mit <b>Bei Fehler <\/b>ein Ereignis, dass genau bei solchen Fehlern ausgel&ouml;st wird. Die dadurch ausgel&ouml;ste Prozedur hat zwei Parameter &#8211; <b>DataErr <\/b>und <b>Response<\/b>.<\/p>\n<p>Mit <b>DataErr <\/b>wird die &uuml;blicherweise mit <b>Err.Number <\/b>ermittelte Fehlernummer &uuml;bergeben, welche den Fehler ausgel&ouml;st hat. F&uuml;r den Fall der Eingabe eines falschen Datums lautet diese Nummer <b>2113<\/b>. Diese pr&uuml;fen wir in der Prozedur aus Listing 3.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Error(DataErr<span style=\"color:blue;\"> As Integer<\/span>, Response<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">If <\/span>DataErr = 2113<span style=\"color:blue;\"> Then<\/span>\r\n         Select Case Screen.ActiveControl.Name\r\n             <span style=\"color:blue;\">Case <\/span>\"txtBestelltAm\"\r\n                 <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie ein g&uuml;ltiges Bestelldatum ein.\", vbOKOnly + vbExclamation, _\r\n                     \"Bestelldatum ist ung&uuml;ltig\"\r\n                 Response = acDataErrContinue\r\n             <span style=\"color:blue;\">Exit Sub<\/span>\r\n         <span style=\"color:blue;\">End Select<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Validierungen, die durch einen Formularfehler ausgel&ouml;st werden<\/span><\/b><\/p>\n<p>Hier pr&uuml;fen wir au&szlig;erdem noch mit <b>Screen.ActiveControl.Name<\/b>, welches Steuerelement zur Zeit des Ausl&ouml;sens des Fehlers aktiv war. Handelt es sich um das Textfeld <b>txtBestelltAm<\/b>, behandeln wir dies im <b>Case<\/b>-Fall des folgenden <b>Select Case<\/b>-Konstrukts.<\/p>\n<p>Hier geben wir wieder eine entsprechende Meldung aus und stellen au&szlig;erdem den zweiten Parameter, der ein R&uuml;ckgabeparameter ist, auf den Wert <b>acDataErrContinue <\/b>ein. Das bedeutet, dass die eigentlich von Access zu diesem Zeitpunkt abgesetzte Fehlermeldung unterbunden werden soll. So erhalten wir schlie&szlig;lich unsere eigene Meldung, wenn der Benutzer ein ung&uuml;ltiges Datum eingibt.<\/p>\n<h2>Validierung f&uuml;r eindeutige Felder<\/h2>\n<p>Das Feld <b>Bestellnummer <\/b>ist mit einem eindeutigen Index versehen. Daher wird auch hier ein Fehler gemeldet, wenn der Benutzer f&uuml;r dieses Feld einen bereits in der Tabelle vorhandenen Wert eingibt. Dieser Fehler tritt allerdings erst beim Versuch auf, den Datensatz zu speichern. Wir k&ouml;nnen den Benutzer auch direkt bei der Eingabe darauf hinweisen, falls der Wert bereits vorhanden ist.<\/p>\n<p>Dazu nutzen wir wiederum das Ereignis <b>Vor Aktualisierung<\/b>, diesmal f&uuml;r das Textfeld <b>txtBestellnummer<\/b> (siehe Listing 4).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>txtBestellnummer_BeforeUpdate(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> IsNull(DLookup(\"ID\", \"tblBestellungen\", \"Bestellnummer = ''\" & Me!Bestellnummer & \"''\"))<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Die Bestellnummer ''\" & Me!Bestellnummer & \"'' ist bereits vergeben.\", vbOKOnly + vbExclamation, _\r\n             \"Doppelte Bestellnummer\"\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Pr&uuml;fung auf doppelte Bestellnummer<\/span><\/b><\/p>\n<p>Die <b>If&#8230;Then<\/b>-Bedingung nutzt eine <b>DLookup<\/b>-Anweisung, um zu pr&uuml;fen, ob es bereits einen Datensatz in der Tabelle <b>tblBestellungen <\/b>gibt, dessen Feld <b>Bestellnummer <\/b>den in das Textfeld eingegebenen Wert enth&auml;lt. Ist das der Fall, erscheint die Meldung aus Bild 16. Nach der Best&auml;tigung wird die Eingabe mit <b>Cancel = True <\/b>abgebrochen und die Prozedur verlassen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_016.png\" alt=\"Meldung bei Eingabe einer bereits vorhandenen Bestellnummer\" width=\"524,559\" height=\"239,6765\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 16: Meldung bei Eingabe einer bereits vorhandenen Bestellnummer<\/span><\/b><\/p>\n<h2>Zahlungsziel<\/h2>\n<p>F&uuml;r das Nachvollziehen der Rechnungseing&auml;nge macht es Sinn, das Feld <b>Zahlungsziel <\/b>zu pflegen, das nat&uuml;rlich auch auf der Rechnung landen soll. Das Feld RechnungAm soll erst gef&uuml;llt werden, wenn die Rechnung tats&auml;chlich geschrieben und versendet wurde. Dann kann man auch das Feld <b>Zahlungsziel <\/b>f&uuml;llen. <\/p>\n<p>Dazu ben&ouml;tigen wir nat&uuml;rlich noch den Zeitraum, der zwischen Rechnungserstellung und dem gew&uuml;nschten Zahlungsziel liegt. Da diese Anzahl der Tage variabel sein soll, wollen wir sie nicht fest verdrahten, sondern diese in einer Tabelle mit Optionen speichern. Dazu kommen wir jedoch erst, wenn wir in einem sp&auml;teren Beitrag die Erstellung des Rechnungsberichts beschreiben &#8211; dort zeigen wir dann auch, wie die Rechnungserstellung beispielsweise vom Formular <b>frmBestellungDetails <\/b>angesto&szlig;en werden kann.<\/p>\n<h2>Anlegen einer Bestellposition<\/h2>\n<p>Nachdem wir die Felder der Tabelle <b>tblBestellungen<\/b>, die der Benutzer im Hauptformular f&uuml;llen soll, beschrieben haben, k&ouml;nnen wir uns um das Unterformular und die dort anzuzeigenden Daten k&uuml;mmern.<\/p>\n<p>Im Optimalfall ben&ouml;tigt der Kunde genau ein Exemplar eines Produkts. Dann braucht der Benutzer nur das Produkt aus dem Kombinationsfeld <b>cboProduktID <\/b>auszuw&auml;hlen. Sie sehen schon &#8211; auch in diesem Unterformular wollen wir die Namen der Steuerelemente mit einem Pr&auml;fix versehen.<\/p>\n<p>Die &uuml;brigen Felder k&ouml;nnten dann direkt mit den entsprechenden Werten gef&uuml;llt werden:<\/p>\n<ul>\n<li><b>Einzelpreis<\/b>: Einzelpreis f&uuml;r das gew&auml;hlte Produkt aus <b>tblProdukte<\/b><\/li>\n<li><b>MwSt.-Satz<\/b>: Mehrwertsteuersatz aus <b>tblProdukte<\/b>\/<b>tblMehrwertsteuersaetze<\/b><\/li>\n<li><b>Menge<\/b>: Standardwert <b>1<\/b><\/li>\n<li><b>Rabatt<\/b>: Standardwert <b>0<\/b><\/li>\n<li><b>Einheit<\/b>: Einheit aus <b>tblProdukte<\/b><\/li>\n<\/ul>\n<p>Im Beitrag <b>Bestellposition per Datenmakro erg&auml;nzen <\/b>(<b>www.access-im-unternehmen.de\/1375<\/b>) zeigen wir, wie Sie diese Werte automatisch erg&auml;nzen lassen k&ouml;nnen, wenn der Benutzer nur das Produkt ausw&auml;hlt und den Datensatz dann speichert. Wenn Sie diese Technik verwenden wollen, brauchen Sie im vorliegenden Formular nichts weiter zu tun &#8211; die &Auml;nderungen werden allein durch das dazu vorgesehene Datenmakro durchgef&uuml;hrt.<\/p>\n<p>Wenn Sie jedoch wollen (was etwas praktischer ist), dass die Daten direkt nach der Auswahl mit den oben genannten Werten ersetzt werden, ben&ouml;tigen Sie eine Ereignisprozedur, die durch das Ereignis <b>Nach Aktualisierung <\/b>des Kombinationsfeldes <b>cboProduktID <\/b>ausgel&ouml;st wird. Diese Prozedur ermittelt den Datensatz der Tabelle <b>tblProdukte<\/b>, den der Benutzer im Kombinationsfeld ausgew&auml;hlt hat, und referenziert diesen mit einem Recordset (siehe Listing 5). Dann liest er die einzelnen Werte aus diesem heraus und tr&auml;gt sie f&uuml;r die Felder der Datensatzquelle des Unterformulars ein. Beim Feld <b>Mehrwertsteuersatz <\/b>ist etwas mehr Aufwand erforderlich: Dieser muss erst noch mit einem <b>DLookup<\/b>-Aufruf aus der Tabelle <b>tblMehrwertsteuersaetze <\/b>ausgelesen werden.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cboProduktID_AfterUpdate()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM tblProdukte WHERE ID = \" & Me!cboProduktID, dbOpenDynaset)\r\n     Me!txtEinzelpreis = rst!Einzelpreis\r\n     Me!txtMehrwertsteuersatz = DLookup(\"Mehrwertsteuersatzwert\", \"tblMehrwertsteuersaetze\", \"ID = \" _\r\n         & rst!MehrwertsteuersatzID)\r\n     Me!txtMenge = 1\r\n     Me!txtRabatt = 0\r\n     Me!cboEinheitID = rst!EinheitID\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Erg&auml;nzen der Bestellposition<\/span><\/b><\/p>\n<p>Das Ergebnis nach der Auswahl eines Eintrags mit dem Kombinationsfeld <b>cboProduktID<\/b> sehen Sie in Bild 17.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_017.png\" alt=\"Automatisches Hinzuf&uuml;gen von Informationen zur Bestellposition\" width=\"624,559\" height=\"353,7964\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 17: Automatisches Hinzuf&uuml;gen von Informationen zur Bestellposition<\/span><\/b><\/p>\n<h2>Validierung der Bestellpositionen<\/h2>\n<p>Nun wollen wir auch die Felder der Bestellposition noch validieren. F&uuml;r das Feld <b>ProduktID <\/b>muss auf jeden Fall ein Wert ausgew&auml;hlt werden, daher gilt dieser die erste Validierung aus der Prozedur aus Listing 6, die &uuml;brigens durch das Ereignis <b>Vor Aktualisierung <\/b>ausgel&ouml;st wird.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_BeforeUpdate(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">If <\/span>IsNull(Me!cboProduktID)<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte w&auml;hlen Sie ein Produkt aus.\", vbOKOnly + vbExclamation, \"Produkt fehlt\"\r\n         Me!cboProduktID.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>Nz(Me!txtMenge, 0) &lt;= 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie eine Menge gr&ouml;&szlig;er 0 ein.\", vbOKOnly + vbExclamation, \"Menge fehlt\"\r\n         Me!txtMenge.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>Nz(Me!txtRabatt, 0) &lt; 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie einen positiven Wert f&uuml;r den Rabatt ein.\", vbOKOnly + vbExclamation, \"Rabatt negativ\"\r\n         Me!txtRabatt.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>IsNull(Me!cboEinheitID)<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte w&auml;hlen Sie eine Einheit aus.\", vbOKOnly + vbExclamation, \"Einheit fehlt\"\r\n         Me!cboEinheitID.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Abschlie&szlig;ende Validierung der Bestellposition<\/span><\/b><\/p>\n<p>Die zweite pr&uuml;ft, ob der Wert des Feldes <b>Menge <\/b>kleiner oder gleich <b>0 <\/b>ist. Ist das der Fall, erscheint eine entsprechende Meldung und das Feld erh&auml;lt den Fokus. Die dritte Validierung betrifft das Feld <b>Rabatt<\/b>. Dieser Wert soll lediglich nicht kleiner als <b>0 <\/b>sein.<\/p>\n<p>Und f&uuml;r das Feld <b>EinheitID <\/b>muss genau wie f&uuml;r das Feld <b>ProduktID <\/b>ebenfalls ein Eintrag des Kombinationsfeldes ausgew&auml;hlt werden.<\/p>\n<h2>Eingebaute Fehlermeldungen abfangen<\/h2>\n<p>Bei den numerischen Feldern ist es au&szlig;erdem sinnvoll, auf Fehler durch die Restriktionen durch den Datentyp zu pr&uuml;fen. Das erledigen wir wieder in der Ereignisprozedur, die durch das Ereignis <b>Bei Fehler <\/b>des Unterformulars ausgel&ouml;st wird. Vielleicht kommt ein Benutzer auf die Idee, f&uuml;r den Einzelpreis einen Wert wie 12$ einzugeben. Dann erscheint logischerweise eine Fehlermeldung wie die aus Bild 18.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_018.png\" alt=\"Eingebauter Fehler bei Eingabe einer ung&uuml;ltigen Einheit im Feld Einzelpreis\" width=\"700\" height=\"383,5221\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 18: Eingebauter Fehler bei Eingabe einer ung&uuml;ltigen Einheit im Feld Einzelpreis<\/span><\/b><\/p>\n<p>Um solche Meldungen abzufangen, richten wir die Prozedur <b>Form_Error <\/b>wie in Listing 7 ein. Die Prozedur f&auml;ngt wieder den Fehler <b>2113 <\/b>ab (diesmal in einer <b>Select Case<\/b>-Bedingung &#8211; warum, sehen Sie weiter unten), der durch Verletzungen der Restriktionen wie in diesem Fall des Datentyps entstehen. Im Gegensatz zu der gleichnamigen Ereignisprozedur, die wir weiter oben f&uuml;r das Hauptformular angelegt haben, pr&uuml;fen wir hier gleich mehrere Felder. Daher finden Sie auch die entsprechende Anzahl von <b>Case<\/b>-Zweigen in der <b>Select Case<\/b>-Bedingung.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Error(DataErr<span style=\"color:blue;\"> As Integer<\/span>, Response<span style=\"color:blue;\"> As Integer<\/span>)\r\n     Select Case DataErr\r\n         <span style=\"color:blue;\">Case <\/span>2113\r\n             Select Case Screen.ActiveControl.Name\r\n                 <span style=\"color:blue;\">Case <\/span>\"txtEinzelpreis\"\r\n                     <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie einen g&uuml;ltigen Einzelpreis ein.\", vbOKOnly + vbExclamation, _\r\n                         \"Einzelpreis ist ung&uuml;ltig\"\r\n                     Response = acDataErrContinue\r\n                     <span style=\"color:blue;\">Exit Sub<\/span>\r\n                 <span style=\"color:blue;\">Case <\/span>\"txtMehrwertsteuersatz\"\r\n                     <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie einen g&uuml;ltigen Mehrwertsteuersatz ein.\", vbOKOnly + vbExclamation, _\r\n                         \"Mehrwertsteuersatz ist ung&uuml;ltig\"\r\n                     Response = acDataErrContinue\r\n                     <span style=\"color:blue;\">Exit Sub<\/span>\r\n                 <span style=\"color:blue;\">Case <\/span>\"txtMenge\"\r\n                     <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie eine g&uuml;ltigen Menge ein.\", vbOKOnly + vbExclamation, \"Menge ist ung&uuml;ltig\"\r\n                     Response = acDataErrContinue\r\n                     <span style=\"color:blue;\">Exit Sub<\/span>\r\n                 <span style=\"color:blue;\">Case <\/span>\"txtRabatt\"\r\n                     <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie einen g&uuml;ltigen Rabatt ein.\", vbOKOnly + vbExclamation, \"Rabatt ist ung&uuml;ltig\"\r\n                     Response = acDataErrContinue\r\n                     <span style=\"color:blue;\">Exit Sub<\/span>\r\n             <span style=\"color:blue;\">End Select<\/span>\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span> <\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Abfangen von Fehlern bei der Eingabe von Werten in das Unterformular<\/span><\/b><\/p>\n<h2>Doppelte Datens&auml;tze in den Bestellpositionen<\/h2>\n<p>Wir haben das Datenmodell so ausgelegt, dass in der Tabelle <b>tblBestellpositionen <\/b>jede Kombination aus <b>BestellungID <\/b>und <b>ProduktID <\/b>nur einmal vorkommen darf. Wir m&uuml;ssen auch noch die Meldung unterbinden, die erscheint, wenn der Benutzer dennoch versehentlich die gleiche Kombination ein zweites Mal eingeben m&ouml;chte.<\/p>\n<p>Auch dies fangen wir in der Ereignisprozedur ab, die durch das Ereignis <b>Bei Fehler <\/b>des Unterformulars ausgel&ouml;st wird. Deshalb haben wir weiter oben auch direkt eine <b>Select Case<\/b>-Bedingung zum Abfragen der Fehlernummer aus dem Parameter <b>DataErr <\/b>angelegt.<\/p>\n<p>Hier f&uuml;gen wir nun einen weiteren Zweig mit dem Wert <b>3022<\/b> hinzu &#8211; dies entspricht dem Fehler, der beim Hinzuf&uuml;gen mehrfach vorkommender Werte f&uuml;r einzelne oder mehrere Felder mit eindeutigem Index ausgel&ouml;st wird (siehe Listing 8).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Error(DataErr<span style=\"color:blue;\"> As Integer<\/span>, Response<span style=\"color:blue;\"> As Integer<\/span>)\r\n     Select Case DataErr\r\n         <span style=\"color:blue;\">Case <\/span>2113\r\n             ...\r\n         <span style=\"color:blue;\">Case <\/span>3022\r\n             <span style=\"color:blue;\">MsgBox<\/span> \"Dieses Produkt ist bereits in der Bestellung enthalten.\", _\r\n                 vbOKOnly + vbExclamation, \"Doppeltes Produkt\"\r\n             Me!cboProduktID.SetFocus\r\n             Response = acDataErrContinue\r\n             <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span> <\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 8: Abfangen von Fehlern bei der mehrfachen Eingabe des gleichen Produkts in das Unterformular<\/span><\/b><\/p>\n<p>F&uuml;gt der Benutzer nun wie in Bild 19 ein Produkt zum zweiten Mal zu einer Bestellung hinzu, erscheint eine entsprechende Meldung und das Steuerelement <b>cboProduktID <\/b>wird selektiert.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1382_019.png\" alt=\"Anzeige einer Meldung, wenn ein Produkt zum zweiten Mal in einer Bestellung landet\" width=\"674,559\" height=\"484,3463\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 19: Anzeige einer Meldung, wenn ein Produkt zum zweiten Mal in einer Bestellung landet<\/span><\/b><\/p>\n<h2>Weitere Formularanpassungen<\/h2>\n<p>Wir wollen das Formular zum Verwalten von Bestellungen von verschiedenen anderen Stellen aus &ouml;ffnen, und zwar in zwei verschiedenen Modi:<\/p>\n<ul>\n<li>zum Anlegen einer neuen Bestellung<\/li>\n<li>zum Bearbeiten einer vorhandenen Bestellung<\/li>\n<\/ul>\n<p>Das Anlegen einer neuen Bestellung wollen wir von folgenden Stellen aus ausl&ouml;sen:<\/p>\n<ul>\n<li>direkt aus dem Ribbon<\/li>\n<li>von einem Formular zur Anzeige aller Bestellungen<\/li>\n<li>vom Formular mit Kundendetails<\/li>\n<\/ul>\n<p>Das Bearbeiten einer vorhandenen Bestellung l&ouml;sen wir von hier aus:<\/p>\n<ul>\n<li>von einem Formular zur Anzeige aller Bestellungen<\/li>\n<li>vom Formular mit Kundendetails<\/li>\n<\/ul>\n<p>Damit neu angelegte oder ge&auml;nderte Bestellungen direkt in den jeweils aufrufenden Formularen angezeigt werden k&ouml;nnen, wollen wir das Formular mit den Bestelldetails als modalen Dialog aufrufen.<\/p>\n<p>Damit k&ouml;nnen wir den Zeitpunkt abfangen, an dem der Benutzer das Formular wieder schlie&szlig;t und die <b>Requery<\/b>-Methode f&uuml;r das jeweils anzeigende Element ausl&ouml;sen.<\/p>\n<p>Wenn wir nun noch das Schlie&szlig;en des Formulars <b>frmBestellungDetails <\/b>so gestalten, dass dieses nicht direkt geschlossen wird, sondern erst nach dem Requery, k&ouml;nnen wir auch noch auf den dort bearbeiteten beziehungsweise neu angelegten Datensatz zugreifen und diesen im aufrufenden Element markieren, damit der Benutzer bei der R&uuml;ckkehr zum jeweiligen &Uuml;bersichtsformular direkt sieht, welchen Datensatz er soeben bearbeitet oder angelegt hat.<\/p>\n<p>Dazu w&uuml;rde man normalerweise eine <b>OK<\/b>-Schaltlf&auml;che mit der folgenden Ereignisprozedur ausstatten:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdOK_Click()\r\n     Me.Visible = <span style=\"color:blue;\">False<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>In der Ereignisprozedur des aufrufenden Formulars w&uuml;rden wir nun etwa so den aktuellen Datensatz auslesen und das Formular endg&uuml;ltig schlie&szlig;en:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdNeueBestellung_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>lngNeueBestellungID<span style=\"color:blue;\"> As Long<\/span>\r\n     DoCmd.OpenForm \"frmBestellungDetails\", _\r\n         WindowMode:=acDialog, DataMode:=acFormAdd\r\n     <span style=\"color:blue;\">If <\/span>IstFormularGeoeffnet(\"frmBestellungDetails\")<span style=\"color:blue;\"> Then<\/span>\r\n         lngNeueBestellungID = Forms!frmBestellungDetails!ID\r\n         DoCmd.Close acForm, \"frmBestellungDetails\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"Neue Bestellung: \" & lngNeueBestellungID\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Wenn der Benutzer das Formular nun allerdings &uuml;ber das Ribbon aufgerufen hat und nicht von einem anderen Formular aus, wird das Formular <b>frmBestellungDetails <\/b>beim Klick auf <b>OK <\/b>lediglich unsichtbar gemacht, aber nicht geschlossen. Das f&uuml;hrt zu Problemen, wenn das Formular anschlie&szlig;end erneut mit <b>DoCmd.OpenForm <\/b>ge&ouml;ffnet wird. <\/p>\n<p>Also haben wir zwei M&ouml;glichkeiten: Wir statten auch das Ereignis, dass durch einen Ribbon-Button ausgel&ouml;st wird, mit der Anweisung zum Schlie&szlig;en des Formulars aus oder wir pr&uuml;fen im Formular <b>frmBestellungDetails<\/b>, von welchem Element aus dieses ge&ouml;ffnet wurde. Ersteres scheint einfacher zu sein, daher w&auml;hlen wir diese M&ouml;glichkeit &#8211; siehe Beitrag <b>Rechnungsverwaltung: Ribbon-Steuerung <\/b>(<b>www.access-im-unternehmen.de\/1399<\/b>).<\/p>\n<p>In beiden F&auml;llen wollen wir jedoch daf&uuml;r sorgen, dass der Benutzer nur jeweils den neuen oder den zu bearbeitenden Datensatz zu Gesicht bekommt und auch nicht zu anderen Datens&auml;tzen navigieren kann.<\/p>\n<p>Deshalb stellen wir die Eigenschaften <b>Navigationsschaltfl&auml;chen<\/b>, <b>Datensatzmarkierer <\/b>und <b>Bildlaufleiste <\/b>des Formulars auf den Wert <b>Nein<\/b> ein. Au&szlig;erdem soll das Formular als modaler Dialog in der Mitte des Accessfensters erscheinen, weshalb wir die Eigenschaft <b>Automatisch zentrieren <\/b>auf <b>Ja <\/b>einstellen.<\/p>\n<p>Damit auch das Navigieren zu anderen Datens&auml;tzen durch Bet&auml;tigen der Tabulaturtaste vom ersten und letzten Steuerelement der Aktivierreihenfolge unterbunden wird, stellen wir die Eigenschaft <b>Zyklus <\/b>auf <b>Aktueller Datensatz <\/b>ein.<\/p>\n<h2>Abbrechen-Schaltfl&auml;che?<\/h2>\n<p>Wenn wir in Access im Unternehmen eine <b>OK<\/b>-Schaltfl&auml;che zu einem Formular hinzuf&uuml;gen, ist meist auch eine <b>Abbrechen<\/b>-Schaltfl&auml;che nicht weit. Diese setzt unproblematisch seit dem letzten Speichern des Datensatzes durchgef&uuml;hrte &Auml;nderungen zur&uuml;ck.<\/p>\n<p>Das Problem bei der Konstellation aus Haupt- und Unterformular, wie sie hier vorliegt, ist das zwischenzeitliche Speichern der Daten im Hauptformular, wenn der Benutzer zum Unterformular wechselt, um die Bestellpositionen einzutragen.<\/p>\n<p>Das k&ouml;nnen Sie gut beobachten, wenn der Datensatzmarkierer noch angezeigt wird. Legen Sie beispielsweise einen neuen Bestelldatensatz an, befindet sich dieser zun&auml;chst im Bearbeitungszustand, was auch an der Anzeige des Stift-Symbols oben im Datensatzmarkierer zu erkennen ist. Bis hierher kann man eine <b>Abbrechen<\/b>-Schaltfl&auml;che mit folgendem Code verwenden, um die &Auml;nderungen r&uuml;ckg&auml;ngig zu machen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdAbbrechen_Click()\r\n     Me.Undo\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Wechselt der Benutzer jedoch dann zum Unterformular, um die Bestellpositionen hinzuzuf&uuml;gen, wird der Datensatz im Hauptformular gespeichert (der Stift im Datensatzmarkierer verschwindet dann).<\/p>\n<p>Das Vorhandensein der <b>Abbrechen<\/b>-Schaltfl&auml;che suggeriert dem Benutzer allerdings, dass er die Eingabe immer noch abbrechen kann, was aber nicht der Fall ist. Wenn wir eine <b>Abbrechen<\/b>-Schaltfl&auml;che hinzuf&uuml;gen, sollte diese deaktiviert werden, wenn kein Abbrechen mehr m&ouml;glich ist.<\/p>\n<p>Allerdings m&uuml;sste man diese auch wieder aktivieren, wenn der Benutzer nun zum Hauptformular zur&uuml;ckkehrt und dort weitere &Auml;nderungen vornimmt. Der Benutzer wei&szlig; dann aber gegebenenfalls nicht, dass das Bet&auml;tigen der <b>Abbrechen<\/b>-Schaltfl&auml;che lediglich die &Auml;nderungen seit der R&uuml;ckkehr zum Hauptformular r&uuml;ckg&auml;ngig macht.<\/p>\n<p>Wir haben in einem &auml;lteren Beitrag zwar gezeigt, dass es m&ouml;glich ist, &Auml;nderungen seit der Anzeige eines Datensatzes in Haupt- und Unterformular r&uuml;ckg&auml;ngig zu machen, aber dieses Verfahren ist relativ kompliziert. Daher entscheiden wir uns an dieser Stelle, dass wir keine <b>Abbrechen<\/b>-Schaltfl&auml;che zum Formular hinzuf&uuml;gen.<\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Dieser Beitrag beschreibt die Erstellung von Haupt- und Unterformular zur Verwaltung von Bestellungen und Bestellpositionen.<\/p>\n<p>In weiteren Beitr&auml;gen stellen wir die &uuml;brigen Formulare der Anwendung vor sowie ein Ribbon, mit dem die Formulare nach dem Start der Anwendung aufgerufen werden k&ouml;nnen.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>RechnungsverwaltungBestellformular.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/C7B058BC-105F-44BF-AEB1-0BA0687B5008\/aiu_1382.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nachdem wir das Datenmodell f&uuml;r unsere Rechnungsverwaltung angelegt sowie die Tabellen mit Beispieldaten gef&uuml;llt haben, kommt als N&auml;chstes die Benutzeroberfl&auml;che zum Verwalten der Kunden-, Produkt- und Bestelldaten an die Reihe. Die dazu notwendigen Formulare stellen wir in mehreren Teilen dieser Beitragsreihe vor. Die Basis ist das Formular zum Anzeigen der Bestellungen, mit dem wir den Kunden ausw&auml;hlen, die Bestelldaten eingeben und die Bestellpositionen hinzuf&uuml;gen k&ouml;nnen. Die Programmierung dieses Formulars zeigen wir im vorliegenden Beitrag &#8211; inklusive Validierung und mehr.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662022,66052022,44000023],"tags":[],"class_list":["post-55001382","post","type-post","status-publish","format-standard","hentry","category-662022","category-66052022","category-Mit_Formularen_arbeiten"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Rechnungsverwaltung: Bestellformular - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Rechnungsverwaltung: Bestellformular\" \/>\n<meta property=\"og:description\" content=\"Nachdem wir das Datenmodell f&uuml;r unsere Rechnungsverwaltung angelegt sowie die Tabellen mit Beispieldaten gef&uuml;llt haben, kommt als N&auml;chstes die Benutzeroberfl&auml;che zum Verwalten der Kunden-, Produkt- und Bestelldaten an die Reihe. Die dazu notwendigen Formulare stellen wir in mehreren Teilen dieser Beitragsreihe vor. Die Basis ist das Formular zum Anzeigen der Bestellungen, mit dem wir den Kunden ausw&auml;hlen, die Bestelldaten eingeben und die Bestellpositionen hinzuf&uuml;gen k&ouml;nnen. Die Programmierung dieses Formulars zeigen wir im vorliegenden Beitrag - inklusive Validierung und mehr.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2022-10-03T14:37:05+00:00\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"27\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Bestellformular\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Bestellformular\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Rechnungsverwaltung: Bestellformular\",\"datePublished\":\"2022-10-03T14:37:05+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Bestellformular\\\/\"},\"wordCount\":4830,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"articleSection\":[\"2022\",\"5\\\/2022\",\"Mit Formularen arbeiten\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Bestellformular\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Bestellformular\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Bestellformular\\\/\",\"name\":\"Rechnungsverwaltung: Bestellformular - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"datePublished\":\"2022-10-03T14:37:05+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Bestellformular\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Bestellformular\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Bestellformular\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Rechnungsverwaltung: Bestellformular\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Rechnungsverwaltung: Bestellformular - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/","og_locale":"de_DE","og_type":"article","og_title":"Rechnungsverwaltung: Bestellformular","og_description":"Nachdem wir das Datenmodell f&uuml;r unsere Rechnungsverwaltung angelegt sowie die Tabellen mit Beispieldaten gef&uuml;llt haben, kommt als N&auml;chstes die Benutzeroberfl&auml;che zum Verwalten der Kunden-, Produkt- und Bestelldaten an die Reihe. Die dazu notwendigen Formulare stellen wir in mehreren Teilen dieser Beitragsreihe vor. Die Basis ist das Formular zum Anzeigen der Bestellungen, mit dem wir den Kunden ausw&auml;hlen, die Bestelldaten eingeben und die Bestellpositionen hinzuf&uuml;gen k&ouml;nnen. Die Programmierung dieses Formulars zeigen wir im vorliegenden Beitrag - inklusive Validierung und mehr.","og_url":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/","og_site_name":"Access im Unternehmen","article_published_time":"2022-10-03T14:37:05+00:00","author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"27\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Rechnungsverwaltung: Bestellformular","datePublished":"2022-10-03T14:37:05+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/"},"wordCount":4830,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"articleSection":["2022","5\/2022","Mit Formularen arbeiten"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/","url":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/","name":"Rechnungsverwaltung: Bestellformular - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"datePublished":"2022-10-03T14:37:05+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Bestellformular\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Rechnungsverwaltung: Bestellformular"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001382","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55001382"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001382\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001382"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001382"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001382"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}