{"id":55001198,"date":"2019-08-01T00:00:00","date_gmt":"2020-05-13T20:55:43","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1198"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/","title":{"rendered":"Datenblatt: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg06.met.vgwort.de\/na\/0373440d9a5f477393d729c6528efd4c\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Wir haben bereits in mehreren Beitr&auml;gen beschrieben, wie Sie die individuelle Reihenfolge von Elementen einer Tabelle &uuml;ber den Inhalt eines Feldes etwa namens &#8222;ReihenfolgeID&#8220; einstellen k&ouml;nnen &#8211; zum Beispiel in Listenfeldern oder Unterformularen in der Datenblattansicht. Dort haben wir die Reihenfolge dann durch Markieren der Eintr&auml;ge und anschlie&szlig;endes Bet&auml;tigen etwa von Schaltfl&auml;chen mit Beschriftungen wie &#8222;Ganz nach oben&#8220;, &#8222;Nach oben&#8220;, &#8222;Nach unten&#8220; oder &#8222;Ganz nach unten&#8220; ge&auml;ndert. Im vorliegenden Beitrag schauen wir uns nun an, wie wir im Unterformular in der Datenblattansicht die Reihenfolge f&uuml;r mehrere Eintr&auml;ge gleichzeitig &auml;ndern k&ouml;nnen.<\/b><\/p>\n<h2>Mehrfach-Reihenfolge im Datenblatt<\/h2>\n<p>Im Beitrag <b>Listenfeld: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern <\/b>(<b>www.access-im-unternehmen.de\/1197<\/b>) zeigen wir, wie das &Auml;ndern der Reihenfolge mehrerer markierter Eintr&auml;ge gleichzeitig im Listenfeld funktioniert. Aber oft sollen Daten auch in einem Unterformular in der Datenblattansicht dargestellt werden, was Vorteile gegen&uuml;ber einem Listenfeld bietet &#8211; zum Beispiel das schnelle Sortieren, Filtern oder das &Auml;ndern der Spaltenanordnung oder -breite.<\/p>\n<p>Au&szlig;erdem kann der Benutzer in einem Unterformular in der Datenblattansicht auch direkt Daten &auml;ndern, was im Listenfeld nicht m&ouml;glich ist. Also zeigen wir auch f&uuml;r das Unterformular in der Datenblattansicht, wie Sie die Reihenfolge der markierten Datens&auml;tze &auml;ndern k&ouml;nnen.<\/p>\n<h2>Beispielformular<\/h2>\n<p>Die Beispielkonstellation sieht wie in Bild 1 aus. Hier haben wir ein Unterformular namens <b>sfmMehrfachreihenfolgeDatenblatt <\/b>erstellt, dass an die Tabelle <b>tblKategorien <\/b>gebunden ist &#8211; und zwar &uuml;ber die folgende SQL-Abfrage:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_04\/pic_1198_001.png\" alt=\"Entwurf des Formulars frmMehrreihenfolgeDatenblatt\" width=\"474,6776\" height=\"329,2119\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Entwurf des Formulars frmMehrreihenfolgeDatenblatt<\/span><\/b><\/p>\n<pre>SELECT tblKategorien.KategorieID, tblKategorien.Kategoriename, tblKategorien.ReihenfolgeID FROM tblKategorien ORDER BY tblKategorien.ReihenfolgeID;<\/pre>\n<p>Dadurch werden die Datens&auml;tze aufsteigend nach der Sortierung des Feldes <b>ReihenfolgeID <\/b>angezeigt.<\/p>\n<p>Das Unterformular soll die Daten der drei Felder <b>KategorieID<\/b>, <b>Kategoriename <\/b>und <b>ReihenfolgeID <\/b>anzeigen. F&uuml;r die Eigenschaft <b>Standardansicht <\/b>haben wir den Wert <b>Datenblatt <\/b>eingestellt.<\/p>\n<p>Danach haben wir das Unterformular aus dem Navigationsbereich von Access in den Entwurf des Hauptformulars <b>frmMehrfachreihenfolgeDatenblatt <\/b>gezogen. Das Unterformularsteuerelement, in dem das Unterformular angezeigt wird, haben wir aus Gr&uuml;nden der &Uuml;bersicht in <b>sfm <\/b>umbenannt.<\/p>\n<p>Rechts neben dem Unterformular befinden sich die vier Schaltfl&auml;chen <b>cmdTop<\/b>, <b>cmdUp<\/b>, <b>cmdDown <\/b>und <b>cmdBottom<\/b>. Die Eigenschaften <b>Navigationsschaltfl&auml;chen<\/b>, <b>Datensatzmarkierer<\/b>, <b>Trennlinien <\/b>und <b>Bildlaufleisten <\/b>des Hauptformulars haben wir auf <b>Nein <\/b>eingestellt, die Eigenschaft <b>Automatisch zentrieren <\/b>auf <b>Ja<\/b>.<\/p>\n<h2>Beschreibung der Aufgabe<\/h2>\n<p>Im Gegensatz zum Listenfeld k&ouml;nnen wir mit der Datenblattansicht nur zusammenh&auml;ngende Datens&auml;tze markieren. Daf&uuml;r gibt es beim Datenblatt ganz andere M&ouml;glichkeiten, um die jeweils markierten Datens&auml;tze zu identifizieren. Diese werden Sie in den folgenden Abschnitten kennenlernen.<\/p>\n<p>Im ersten Schritt wollen wir sicherstellen, dass jeweils nur die aktuell notwendigen Schaltfl&auml;chen aktiviert sind. Das hei&szlig;t, dass die beiden Schaltfl&auml;chen <b>cmdTop <\/b>und <b>cmdUp <\/b>deaktiviert werden sollen, wenn der Benutzer den obersten Datensatz im Datenblatt markiert hat, denn dann k&ouml;nnen die markierten Elemente nicht mehr weiter nach oben verschoben werden. Das gleiche gilt f&uuml;r die Schaltfl&auml;chen <b>cmdDown <\/b>und <b>cmdBottom<\/b>, wenn der letzte Datensatz im Datenblatt markiert ist. Wenn der Benutzer alle Datens&auml;tze markiert, sollen dementsprechend alle vier Schaltfl&auml;chen deaktiviert sein.<\/p>\n<p>Eine besondere Herausforderung besteht darin, dass beim Wechseln der Markierung im Unterformular Steuer-elemente im Hauptformular ge&auml;ndert sollen. Es ist zwar einfach m&ouml;glich, dies &uuml;ber eine entsprechende Ereignisprozedur im Unterformular zu realisieren. Diese w&uuml;rde dann etwa &uuml;ber <b>Me.Parent.cmdUp <\/b>auf die Schaltfl&auml;che <b>cmdUp <\/b>zugreifen. Sch&ouml;ner und wartungsfreundlicher ist es allerdings, wenn der Code im Hauptformular versammelt ist. Das hei&szlig;t, dass wir im Hauptformular eine Objektvariable zum Referenzieren des Unterformulars deklarieren und f&uuml;r diese Objektvariable die Ereignisse implementieren, die normalerweise im Klassenmodul des Unterformulars gelandet w&auml;ren.<\/p>\n<h2>Aktivieren und Deaktivieren der Schaltfl&auml;chen<\/h2>\n<p>Die Schaltfl&auml;chen sollen in Abh&auml;ngigkeit von den aktuell markierten Eintr&auml;gen des Unterformulars aktiviert und deaktiviert werden. Das Problem dabei ist, dass wir erst noch ein Ereignis finden m&uuml;ssen, dass beim Setzen der Markierung im Unterformular ausgel&ouml;st wird. Das Ereignis  <b>Bei Markierungs&auml;nderung <\/b>h&ouml;rt sich spannend an, aber es kann nur in der veralteten <b>PivotChart<\/b>&#8211; oder <b>PivotTable<\/b>-Ansicht eingesetzt werden.<\/p>\n<p>Also nutzen wir die <b>Bei Maustaste auf<\/b>-Ereigniseigenschaft eines der Bereiche des Unterformulars. Wir finden schnell heraus, dass dieses Ereignis f&uuml;r das Formular selbst ausgel&ouml;st wird, wenn wir auf einen der Datensatzmarkierer klicken, also auf den in Bild 2 markierten Bereich. Im Unterformular selbst sieht die Ereignisprozedur wie folgt aus:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_04\/pic_1198_002.png\" alt=\"Bereich, der das Ereignis OnMouseDown ausl&ouml;st\" width=\"474,6776\" height=\"287,2364\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Bereich, der das Ereignis OnMouseDown ausl&ouml;st<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_MouseUp(Button<span style=\"color:blue;\"> As Integer<\/span>, _\r\n     Shift<span style=\"color:blue;\"> As Integer<\/span>, X<span style=\"color:blue;\"> As Single<\/span>, Y<span style=\"color:blue;\"> As Single<\/span>)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Wir wollen diese allerdings im Klassenmodul des Hauptformulars implementieren. Dazu deklarieren wir die Variable <b>sfm <\/b>wie folgt:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>WithEvents m_SubForm<span style=\"color:blue;\"> As <\/span>Form<\/pre>\n<p>Bei dieser Gelegenheit deklarieren wir direkt drei Konstanten, die sp&auml;ter oft verwendete Bezeichnungen enthalten &#8211; f&uuml;r die Tabelle, das Prim&auml;rschl&uuml;sselfeld der Tabelle und das Feld, nach dem die Sortierung erfolgt, in diesem Fall <b>ReihenfolgeID<\/b>:<\/p>\n<pre>Const m_Table<span style=\"color:blue;\"> As String<\/span> = \"tblKategorien\"\r\nConst m_PKField<span style=\"color:blue;\"> As String<\/span> = \"KategorieID\"\r\nConst m_Orderfield<span style=\"color:blue;\"> As String<\/span> = \"ReihenfolgeID\"<\/pre>\n<p>Auf diese Weise k&ouml;nnen Sie, wenn Sie den Code dieser L&ouml;sung in anderen Formularen einsetzen wollen, schnell die Bezeichnungen der von Ihnen verwendeten Tabelle und Felder angeben.<\/p>\n<p>Danach f&uuml;llen wir diese Variable in der Prozedur, die durch das Ereignis <b>Beim Laden <\/b>des Hauptformulars ausgel&ouml;st wird, wie folgt:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Set<\/span> m_SubForm = Me!sfm.Form\r\n     m_SubForm.OnMouseUp = \"[Event Procedure]\"\r\n     FillOrderID\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die zweite Anweisung stellt per Code die Eigenschaft <b>Bei Maustaste auf <\/b>des Unterformulars auf den Wert <b>[Ereignisprozedur] <\/b>ein &#8211; diesen Schritt w&uuml;rden Sie normalerweise &uuml;ber das Eigenschaftenblatt erledigen.<\/p>\n<p>Die Prozedur <b>FillOrderID <\/b>f&uuml;llt das in <b>m_Orderfield <\/b>angegebene Feld der Tabelle aus <b>m_Table <\/b>mit durchlaufenden Werten von <b>1 <\/b>bis zur Anzahl der enthaltenen Datens&auml;tze.<\/p>\n<p>Diese Prozedur beschreiben wir ausf&uuml;hrlich im Beitrag <b>Listenfeld: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern <\/b>(<b>www.access-im-unternehmen.de\/1197<\/b>).<\/p>\n<p>Nun hinterlegen wir eine Ereignisprozedur f&uuml;r das Ereignis <b>Bei Maustaste ab <\/b>des Unterformulars.<\/p>\n<p>Dazu w&auml;hlen Sie im Codefenster des Moduls <b>Form_frmMehrfachreihenfolgeDatenblatt <\/b>aus dem linken Kombinationsfeld den Wert <b>m_SubForm <\/b>und aus dem rechten Kombinationsfeld den Wert <b>MouseUp<\/b> aus (siehe Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_04\/pic_1198_003.png\" alt=\"Anlegen des Ereignisses f&uuml;r das Unterformular\" width=\"549,6265\" height=\"397,724\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Anlegen des Ereignisses f&uuml;r das Unterformular<\/span><\/b><\/p>\n<p>Damit das Ereignis auch ausgel&ouml;st wird, m&uuml;ssen Sie f&uuml;r das Unterformular noch ein Klassenmodul anlegen. Dazu k&ouml;nnen Sie einfach die Eigenschaft <b>Enth&auml;lt Modul <\/b>des als Unterformular verwendeten Formulars auf <b>Ja <\/b>einstellen.<\/p>\n<h2>Markierte Datens&auml;tze erkennen<\/h2>\n<p>Die so entstandene Prozedur, die wie folgt aussieht, m&uuml;ssen wir nun noch mit dem Code f&uuml;llen, der die Markierung pr&uuml;ft und die Schaltfl&auml;chen aktiviert oder deaktiviert. Diesen Code lagern wir in eine neue Prozedur namens <b>ActivateControls <\/b>aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>m_SubForm_MouseDown(Button<span style=\"color:blue;\"> As Integer<\/span>, _\r\n         Shift<span style=\"color:blue;\"> As Integer<\/span>, X<span style=\"color:blue;\"> As Single<\/span>, Y<span style=\"color:blue;\"> As Single<\/span>)\r\n     ActivateControls\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Hier geben wir testweise erst einmal die Werte der Eigenschaften <b>SelTop <\/b>und <b>SelHeight <\/b>im Direktbereich aus, um zu pr&uuml;fen, ob diese die entsprechenden Werte zur durchgef&uuml;hrten Markierung liefern:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>ActivateControls()\r\n     <span style=\"color:blue;\">Debug.Print<\/span> m_SubForm.SelTop, m_SubForm.SelHeight\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Das gelingt auch recht gut. Die Eigenschaft <b>SelTop <\/b>liefert immer den 1-basierten Index des ersten markierten Eintrags, die Eigenschaft <b>SelHeight <\/b>die Anzahl der markierten Eintr&auml;ge. Wenn Sie etwa erst auf den Datensatzmarkierer des zweiten Eintrags klicken und dann bei gedr&uuml;ckter <b>Umschalt<\/b>-Taste auf den f&uuml;nften Eintrag, werden vier Eintr&auml;ge vom zweiten bis zum f&uuml;nften Eintrag markiert (siehe Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_04\/pic_1198_005.png\" alt=\"Markieren mehrerer Eintr&auml;ge\" width=\"474,6776\" height=\"261,9551\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Markieren mehrerer Eintr&auml;ge<\/span><\/b><\/p>\n<p>Die Eigenschaft <b>SelTop <\/b>liefert dann den Wert <b>2<\/b>, die Eigenschaft <b>SelHeight <\/b>den Wert <b>4<\/b>. Sie k&ouml;nnen auch mehrere Datens&auml;tze markieren, indem Sie auf den Datensatzmarkierer des ersten zu markierenden Datensatzes klicken und dann bei gedr&uuml;ckter linker Maustaste den Mauszeiger bis zum Datensatzmarkierer des letzten gew&uuml;nschten Datensatzes herunterziehen.<\/p>\n<p>Hier gibt es noch ein paar Besonderheiten:<\/p>\n<ul>\n<li>Wenn das Unterformular das Hinzuf&uuml;gen von Datens&auml;tzen erlaubt, k&ouml;nnen Sie auch die neue, leere Zeile markieren (siehe Bild 5). Dies liefert dann als Ergebnis f&uuml;r die Eigenschaft <b>SelTop <\/b>den Wert <b>9 <\/b>und f&uuml;r die Eigenschaft <b>SelLength <\/b>den Wert <b>1<\/b>. Wie wir dies behandeln, schauen wir uns weiter unten an.<\/li>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_04\/pic_1198_004.png\" alt=\"Markieren des letzten Eintrags\" width=\"474,6776\" height=\"261,9551\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Markieren des letzten Eintrags<\/span><\/b><\/p>\n<li>Sie k&ouml;nnen auch mit der Maus auf den schmalen Bereich zwischen zwei Datensatzmarkierern klicken. Das ist dann der Fall, wenn sich der Mauszeiger zuvor in das Symbol aus Bild 6 verwandelt hat. Hier liefert <b>SelTop <\/b>den Index des darunter liegenden Datensatzes, im Beispiel den Wert <b>6<\/b>. <b>SelLength <\/b>liefert aber zum Gl&uuml;ck den Wert <b>0<\/b>, sodass wir diesen Sonderfall gut behandeln k&ouml;nnen.<\/li>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_04\/pic_1198_006.png\" alt=\"Anklicken des Bereichs zwischen zwei Datens&auml;tzen\" width=\"474,6776\" height=\"261,9551\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Anklicken des Bereichs zwischen zwei Datens&auml;tzen<\/span><\/b><\/p>\n<li>Es gibt noch einen Sonderfall, n&auml;mlich das Markieren aller Datens&auml;tze mit der Tastenkombination <b>Strg + A<\/b>. Das registriert die von uns vorgesehene Ereignisprozedur jedoch nicht, da diese nur auf Mausklicks reagiert. Also m&uuml;ssen wir uns hierf&uuml;r eine Sonderbehandlung &uuml;berlegen, die wir ebenfalls weiter unten vorstellen.<\/li>\n<\/ul>\n<h2>Neuen Datensatz ber&uuml;cksichtigen<\/h2>\n<p>Um den neuen, leeren Datensatz zu ber&uuml;cksichtigen, m&uuml;ssen wir zun&auml;chst einmal herausfinden, ob dieser &uuml;berhaupt eingeblendet wird. Dies gelingt mit der Eigenschaft <b>AllowEditions<\/b>.<\/p>\n<p>Diese fragen wir als Eigenschaft des Unterformulars ab, also etwa mit <b>Me!sfm.Form.AllowAdditions<\/b> und in unserem Fall mit <b>m_SubForm.AllowAdditions<\/b>. Wenn der Benutzer das Hinzuf&uuml;gen von Datens&auml;tzen erlaubt, liefert die Eigenschaft den Wert <b>True<\/b>, sonst <b>False<\/b>.<\/p>\n<p>Damit ergeben sich zwei F&auml;lle:<\/p>\n<ul>\n<li>Der Benutzer k&ouml;nnte bei <b>AllowEditions = True <\/b>auch den neuen, leeren Datensatz markieren.<\/li>\n<li>Bei <b>AllowEditions = False <\/b>kann der Benutzer den neuen, leeren Datensatz nicht markieren, da dieser nicht angezeigt wird.<\/li>\n<\/ul>\n<p>Im zweiten Fall k&ouml;nnen wir als einfach die von <b>SelLength <\/b>gelieferte Anzahl verwenden. Im ersten Fall m&uuml;ssen wir jedoch pr&uuml;fen, ob der Index eines der markierten Eintr&auml;ge der Index des neuen, leeren Datensatzes ist. Und dazu ben&ouml;tigen Sie die Anzahl der Datens&auml;tze des Unterformulars.<\/p>\n<h2>Anzahl der Datens&auml;tze im Unterformular ermitteln<\/h2>\n<p>Die Anzahl der Datens&auml;tze ermitteln wir ganz einfach mit der Eigenschaft <b>RecordCount <\/b>des Recordset-Objekts des Unterformulars:<\/p>\n<pre>m_SubForm.Recordset.RecordCount<\/pre>\n<h2>Schaltfl&auml;chen aktivieren und deaktivieren<\/h2>\n<p>Mit diesen Erkenntnissen k&ouml;nnen wir uns nun um die Prozedur <b>ActivateControls <\/b>k&uuml;mmern (siehe Listing 1). In dieser aktivieren wir nun zuerst alle Schaltfl&auml;chen durch Einstellen der Eigenschaft <b>Enabled <\/b>auf den Wert <b>True<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>ActivateControls()\r\n     <span style=\"color:blue;\">Dim <\/span>bolErster<span style=\"color:blue;\"> As Boolean<\/span>, bolLetzter<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngAnzahl<span style=\"color:blue;\"> As Long<\/span>\r\n     Me!cmdBottom.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     Me!cmdDown.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     Me!cmdTop.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     Me!cmdUp.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     lngAnzahl = m_SubForm.Recordset.RecordCount\r\n     <span style=\"color:blue;\">If <\/span>m_SubForm.SelTop = 1<span style=\"color:blue;\"> Then<\/span>\r\n         bolErster = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>m_SubForm.AllowAdditions = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">If <\/span>m_SubForm.SelTop + m_SubForm.SelHeight - 1 &gt;= lngAnzahl<span style=\"color:blue;\"> Then<\/span>\r\n             bolLetzter = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         <span style=\"color:blue;\">If <\/span>m_SubForm.SelTop + m_SubForm.SelHeight - 1 = lngAnzahl<span style=\"color:blue;\"> Then<\/span>\r\n             bolLetzter = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>m_SubForm.SelHeight = 0<span style=\"color:blue;\"> Then<\/span>\r\n         DisableUp\r\n         DisableDown\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         <span style=\"color:blue;\">If <\/span>bolErster<span style=\"color:blue;\"> Then<\/span>\r\n             DisableUp\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">If <\/span>bolLetzter<span style=\"color:blue;\"> Then<\/span>\r\n             DisableDown\r\n         <span style=\"color:blue;\">End If<\/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 1: Prozedur zum Aktivieren und Deaktivieren der Schaltfl&auml;chen<\/span><\/b><\/p>\n<p>Dann ermitteln wir die Anzahl der enthaltenen Datens&auml;tze und speichern sie in der Variablen <b>lngAnzahl<\/b>. Die beiden Variablen <b>bolErster <\/b>und <b>bolLetzter<\/b> verwenden wir, um einzustellen, dass der Benutzer den ersten und\/oder letzten Datensatz markiert hat.<\/p>\n<p>Anschlie&szlig;end pr&uuml;fen wir, ob die Eigenschaft <b>SelTop<\/b> den Wert <b>1 <\/b>aufweist, was schon einmal bedeutet, dass der erste Datensatz markiert ist. Also stellen wir die Variable <b>bolErster <\/b>auf den Wert <b>True <\/b>ein.<\/p>\n<p>Dann unterscheiden wir nach dem Wert der Eigenschaft <b>AllowEditions<\/b>, wie es weitergeht. Hat sie den Wert <b>True<\/b>, pr&uuml;fen wir, ob der Ausdruck <b>m_SubForm.SelTop + m_SubForm.SelHeight &#8211; 1 >= lngAnzahl <\/b>wahr ist.<\/p>\n<p>Wir ermitteln im ersten Teil also den Index des letzten markierten Eintrags und pr&uuml;fen, ob dieser gr&ouml;&szlig;er oder gleich der Anzahl der Recordsets im Unterformular ist. Ist das der Fall, erh&auml;lt <b>bolLetzter <\/b>den Wert <b>True<\/b>. Im <b>Else<\/b>-Teil pr&uuml;fen wir mit einer &auml;hnlichen Bedingung, die sich nur im Vergleichsoperator von der ersten unterscheidet, ob der Index des letzten markierten Eintrags der Anzahl der Recordsets entspricht und legen dann den Wert von <b>bolLetzter <\/b>auf <b>True <\/b>fest.<\/p>\n<p><!--30percent--><\/p>\n<p>Wenn kein Eintrag markiert ist, <b>SelHeight <\/b>also den Wert <b>0 <\/b>liefert, rufen wir direkt die beiden Prozeduren <b>DisableUp <\/b>und <b>DisableDown <\/b>auf, damit die Schaltfl&auml;chen deaktiviert werden. Anderenfalls rufen wir <b>DisableUp <\/b>nur auf, wenn <b>bolErster <\/b>den Wert <b>True <\/b>hat und <b>DisableDown <\/b>nur dann, wenn <b>bolLetzter <\/b>den Wert <b>True <\/b>hat.<\/p>\n<p>Die beiden Prozeduren <b>DisableUp <\/b>und <b>DisableDown <\/b>deaktivieren nur jeweils die entsprechenden Schaltfl&auml;chen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>DisableUp()\r\n     Me!cmdUp.Enabled = <span style=\"color:blue;\">False<\/span>\r\n     Me!cmdTop.Enabled = <span style=\"color:blue;\">False<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>DisableDown()\r\n     Me!cmdDown.Enabled = <span style=\"color:blue;\">False<\/span>\r\n     Me!cmdBottom.Enabled = <span style=\"color:blue;\">False<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Damit haben wir die Aktivierung und Deaktivierung der Schaltlf&auml;chen erledigt. Diese reagieren jetzt wie gew&uuml;nscht &#8211; siehe Bild 7:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_04\/pic_1198_007.png\" alt=\"Aktivieren und Deaktivieren der Schaltfl&auml;chen abh&auml;ngig von den markierten Datens&auml;tzen\" width=\"474,6776\" height=\"974,436\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Aktivieren und Deaktivieren der Schaltfl&auml;chen abh&auml;ngig von den markierten Datens&auml;tzen<\/span><\/b><\/p>\n<ul>\n<li>Beim &Ouml;ffnen des Formulars ist kein Eintrag markiert, also werden auch alle Schaltfl&auml;chen deaktiviert.<\/li>\n<li>Wenn wir den ersten Datensatz markieren, werden die oberen beiden Schaltfl&auml;chen deaktiviert.<\/li>\n<li>Wenn wir beliebige Datens&auml;tze mit Ausnahme des ersten und letzten Datensatzes markieren, sind alle Schaltfl&auml;chen aktiviert.<\/li>\n<li>Wenn wir den untersten Datensatz markieren, werden die unteren beiden Schaltfl&auml;chen deaktiviert.<\/li>\n<li>Wenn alle Datens&auml;tze markiert sind, sollen alle Schaltfl&auml;chen deaktiviert werden, weil kein Verschieben in irgendeine Richtung mehr m&ouml;glich ist.<\/li>\n<\/ul>\n<p>Allein beim &Ouml;ffnen des Formulars werden die Schaltfl&auml;chen noch nicht richtig eingestellt. Das &auml;ndern wir, indem wir der Ereignisprozedur <b>Beim Laden <\/b>noch den Aufruf von <b>ActivateControls <\/b>hinzuf&uuml;gen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Set<\/span> m_SubForm = Me!sfm.Form\r\n     m_SubForm.OnMouseUp =  \"[Event Procedure]\"\r\n     FillOrderID\r\n     ActivateControls\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Schaltfl&auml;chen Deaktivieren bei Strg + A<\/h2>\n<p>Wenn der Benutzer die Tastenkombination <b>Strg + A <\/b>verwendet, um alle Datens&auml;tze des Datenblatts zu markieren, werden die Schaltfl&auml;chen nicht automatisch deaktiviert. Dazu m&uuml;ssen wir eine weitere Ereignisprozedur hinzuf&uuml;gen, die durch ein Tastenereignis ausgel&ouml;st wird. Welches aber verwenden wir hier Wenn wir uns ansehen, wann beim Bet&auml;tigen von <b>Strg + A <\/b>die Datens&auml;tze markiert werden, stellen wir fest, dass dies bereits beim Herunterdr&uuml;cken der Tastenkombination geschieht. Also k&ouml;nnen wir das Aktivieren und Deaktivieren der Schaltfl&auml;chen f&uuml;r das Ereignis <b>Bei Taste auf <\/b>ausl&ouml;sen, denn dann liegt ja schon die zu untersuchende Markierung vor.<\/p>\n<p>Die n&auml;chste Frage ist, f&uuml;r welche Elemente wir die Ereignisprozedur einrichten m&uuml;ssen. Dazu legen wir Ereignisprozeduren f&uuml;r alle in Frage kommenden Elemente fest und lassen uns den Namen des Elements im Direktbereich ausgeben:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_KeyDown(...)\r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"Form\"\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>KategorieID_KeyDown(...)\r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"KategorieID\"\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>Kategoriename_KeyDown(...)\r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"Kategoriename\"\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>ReihenfolgeID_KeyDown(...)\r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"ReihenfolgeID\"\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Das Ergebnis ist: Das Ereignis wird immer f&uuml;r das zuletzt aktivierte Steuer-element im Unterformular ausgel&ouml;st. Wenn nach dem &Ouml;ffnen des Formulars noch kein Steuer-element aktiviert wurde, weil der Benutzer etwa auf die Navigationsschaltfl&auml;chen geklickt hat, wird automatisch das erste gebundene Steuerelement verwendet, in diesem Fall das Textfeld zur Anzeige des Feldes <b>KategorieID<\/b>. Das hei&szlig;t, wir m&uuml;ssen f&uuml;r alle Steuer-elemente des Unterformulars Ereignisprozeduren definieren, welche die Prozedur <b>ActivateControls <\/b>aufrufen. Das ist mehr Aufwand als erwartet, vor allem, wenn wir den Programmcode auch f&uuml;r das Unterformular und seine Steuer-elemente komplett im Klassenformular des Hauptformulars unterbringen wollen. Wir m&uuml;ssten dann f&uuml;r jedes Steuer-element eine entsprechende Objektvariable unterbringen, f&uuml;r die wir dann die Ereignisprozedur <b>Bei Taste Ab <\/b>implementieren.<\/p>\n<p>Aber wir ben&ouml;tigen noch ein weiteres Ereignis, n&auml;mlich <b>Bei Maustaste ab<\/b>: Denn auch, wenn der Benutzer mit der Maus in eines der Felder klickt, kann es sein, dass dadurch die Markierung ver&auml;ndert wird.<\/p>\n<p>F&uuml;r unseren Fall lagern wir den Code in ein Klassenmodul aus, das die gew&uuml;nschte Funktionalit&auml;t bereitstellt, und legen von dieser Klasse f&uuml;r jedes Steuer-element im Unterformular eine Instanz an. Diese sammeln wir dann in einer Collection, damit sie nach dem Erstellen nicht verloren gehen. Die Klasse sieht wie in Listing 2 aus.<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>m_Control<span style=\"color:blue;\"> As <\/span>Control\r\n<span style=\"color:blue;\">Private <\/span>m_Form<span style=\"color:blue;\"> As <\/span>Form\r\n<span style=\"color:blue;\">Private <\/span>WithEvents txt<span style=\"color:blue;\"> As <\/span>TextBox\r\n<span style=\"color:blue;\">Private <\/span>WithEvents cbo<span style=\"color:blue;\"> As <\/span>ComboBox\r\n<span style=\"color:blue;\">Private <\/span>WithEvents chk<span style=\"color:blue;\"> As <\/span>CheckBox\r\n<span style=\"color:blue;\">Public Property <span style=\"color:blue;\">Set<\/span> <\/span>Control(ctl<span style=\"color:blue;\"> As <\/span>Control)\r\n     <span style=\"color:blue;\">Set<\/span> m_Control = ctl\r\n     Select Case m_Control.ControlType\r\n         <span style=\"color:blue;\">Case <\/span>acTextBox\r\n             <span style=\"color:blue;\">Set<\/span> txt = ctl\r\n             <span style=\"color:blue;\">With<\/span> txt\r\n                 .OnKeyUp = \"[Event Procedure]\"\r\n                 .OnMouseUp = \"[Event Procedure]\"\r\n             End <span style=\"color:blue;\">With<\/span>\r\n         <span style=\"color:blue;\">Case <\/span>acComboBox\r\n             <span style=\"color:blue;\">Set<\/span> cbo = ctl\r\n             <span style=\"color:blue;\">With<\/span> cbo\r\n                 .OnKeyUp = \"[Event Procedure]\"\r\n                 .OnMouseUp = \"[Event Procedure]\"\r\n             End <span style=\"color:blue;\">With<\/span>\r\n         <span style=\"color:blue;\">Case <\/span>acCheckBox\r\n             <span style=\"color:blue;\">Set<\/span> chk = ctl\r\n             <span style=\"color:blue;\">With<\/span> chk\r\n                 .OnKeyUp = \"[Event Procedure]\"\r\n                 .OnMouseUp = \"[Event Procedure]\"\r\n             End <span style=\"color:blue;\">With<\/span>\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Public Property <span style=\"color:blue;\">Set<\/span> <\/span>Form(frm<span style=\"color:blue;\"> As <\/span>Form)\r\n     <span style=\"color:blue;\">Set<\/span> m_Form = frm\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>cbo_KeyUp(KeyCode<span style=\"color:blue;\"> As Integer<\/span>, Shift<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">If <\/span>KeyCode = 65 And Shift = acCtrlMask<span style=\"color:blue;\"> Then<\/span>\r\n         m_Form.ActivateControls\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n... gleiche Prozedur f&uuml;r chk_KeyUp und txt_KeyUp ...\r\n<span style=\"color:blue;\">Private Sub <\/span>cbo_MouseUp(Button<span style=\"color:blue;\"> As Integer<\/span>, Shift<span style=\"color:blue;\"> As <\/span>_\r\n         Integer, X<span style=\"color:blue;\"> As Single<\/span>, Y<span style=\"color:blue;\"> As Single<\/span>)\r\n     m_Form.ActivateControls\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n... gleiche Prozedur f&uuml;r cbo_MouseUp und txt_MouseUp ...<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Inhalt des Klassenmoduls clsControlWrapper<\/span><\/b><\/p>\n<p>Dort deklarieren wir im Kopf einige Variablen. Die erste nimmt einen Verweis auf das gebundene Steuer-element auf, das wir mit Ereignisprozeduren versehen wollen, die zweite einen Verweis auf das Hauptformular. Diesen ben&ouml;tigen wir, weil sich die Prozedur, die wir &uuml;ber die Ereignisprozedur aufrufen wollen, im Klassenmodul des Formulars befindet. <b>m_Form <\/b>werden wir mit einem Verweis auf dieses f&uuml;llen, damit wir auf die Prozedur <b>Activate-Controls <\/b>zugreifen k&ouml;nnen.<\/p>\n<p>Die drei weiteren Variablen sollen je nach Steuerelementtyp einen Verweis auf das Steuer-element aufnehmen. Das erledigen wir in der &ouml;ffentlichen <b>Property Set<\/b>-Eigenschaft Control. Diese nimmt &uuml;ber den Parameter <b>ctl <\/b>einen Verweis auf das gebundene Steuer-element entgegen. Dann pr&uuml;ft sie in einer <b>Select Case<\/b>-Bedingung, ob es sich um ein <b>TextBox<\/b>-, ein <b>ComboBox<\/b>&#8211; oder ein <b>CheckBox<\/b>-Steuerelement handelt. Je nach Steuerelementtyp wird entweder die Variable <b>txt<\/b>, <b>cbo <\/b>oder <b>chk <\/b>mit der Variablen aus <b>ctl <\/b>gef&uuml;llt.<\/p>\n<p>Au&szlig;erdem legt die Prozedur f&uuml;r die entsprechende, mit dem Schl&uuml;sselwort <b>WithEvents <\/b>deklarierte Variable die Eigenschaften <b>OnKeyUp <\/b>und <b>OnMouseUp <\/b>auf den Wert <b>[Event Procedure] <\/b>fest.  <\/p>\n<p>Die <b>Property Set<\/b>-Prozedur <b>Form <\/b>nimmt mit dem Parameter <b>frm <\/b>einen Verweis auf das Hauptformular fest.<\/p>\n<p>Von den drei Ereignisprozeduren <b>cbo_KeyUp<\/b>, <b>chk_KeyUp <\/b>und <b>txt_KeyUp <\/b>verwendet jede Instanz der Klasse nur eine, denn es wird ja nur einer der drei Steuerelementtypen zugewiesen. Die Prozeduren enthalten aber den gleichen Code. Die erste Anweisung pr&uuml;ft, ob der Benutzer gerade die Taste <b>A <\/b>(Parameter <b>KeyCode <\/b>gleich <b>65<\/b>) bei gedr&uuml;ckter Umschalttaste (Parameter <b>Shift <\/b>gleich <b>acCtrlMask<\/b>) bet&auml;tigt hat. Nur in diesem Fall wird in dem mit <b>frm <\/b>referenzierten Hauptformular die Prozedur <b>ActivateControls <\/b>aufgerufen. Damit die Prozedur <b>ActivateControls <\/b>im Klassenmodul des Hauptformulars &uuml;berhaupt von der Klasse aus aufgerufen werden kann, m&uuml;ssen wir noch das Schl&uuml;sselwort <b>Private <\/b>durch <b>Public <\/b>ersetzen:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>ActivateControls()\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Danach brauchen wir nur noch ein paar zus&auml;tzliche Anweisungen in der <b>Form_Load<\/b>-Ereignisprozedur des Hauptformulars sowie eine Variable f&uuml;r die Collection. Diese deklarieren wir im Klassenmodul <b>Form_MehrfachreihenfolgeDatenblatt <\/b>wie folgt:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>colControlWrappers<span style=\"color:blue;\"> As <\/span>Collection<\/pre>\n<p>Die Prozedur <b>Form_Load <\/b>erweitern wir wie folgt, damit f&uuml;r jedes der gebundenen Steuer-elemente im Unterformular eine Instanz der Klasse <b>clsControlWrapper <\/b>erzeugt wird. Als Erstes ben&ouml;tigen wir drei neue Variablen namens <b>strControlSource<\/b>, <b>objControlWrapper<\/b> und <b>ctl<\/b>. Erstere dient der Pr&uuml;fung, ob es sich bei einem Steuer-element um ein gebundenes Steuer-element handelt. Zweiteres nimmt die neue Instanz der Klasse <b>clsControlWrapper <\/b>auf.<\/p>\n<p>Die letzte Variable <b>ctl <\/b>dient zum Durchlaufen der Steuer-elemente des Unterformulars:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Dim <\/span>strControlSource<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objControlWrapper<span style=\"color:blue;\"> As <\/span>clsControlWrapper\r\n     <span style=\"color:blue;\">Dim <\/span>ctl<span style=\"color:blue;\"> As <\/span>Control\r\n     <span style=\"color:blue;\">Set<\/span> m_SubForm = Me!sfm.Form\r\n     m_SubForm.OnMouseUp = \"[Event Procedure]\"\r\n     FillOrderID\r\n     ActivateControls<\/pre>\n<p>In der Prozedur erstellen wir eine neue Collection zum Speichern der Instanzen von <b>clsControlWrapper<\/b>:<\/p>\n<pre>     <span style=\"color:blue;\">Set<\/span> colControlWrappers = <span style=\"color:blue;\">New<\/span> Collection<\/pre>\n<p>Dann durchlaufen wir alle Steuer-elemente des Unterformulars und stellen die Variable <b>strControlSource <\/b>zun&auml;chst auf eine leere Zeichenkette ein. Bei deaktivierter Fehlerbehandlung versuchen wir dann, diese mit dem Inhalt der Eigenschaft <b>ControlSource <\/b>des jeweiligen Steuerelements zu f&uuml;llen.<\/p>\n<p>Ist das Steuer-element nicht gebunden, l&ouml;st dies einen Fehler aus, daher die ausgeschaltete Fehlerbehandlung. Anschlie&szlig;end pr&uuml;fen wir, ob <b>strControlSource <\/b>mit einem Wert gef&uuml;llt wurde &#8211; in diesem Fall handelt es sich um ein gebundenes Steuer-element. Wir erstellen dann eine neue Instanz der Klasse <b>clsControlWrapper <\/b>und speichern diese in der Variablen <b>objControlWrapper<\/b>.<\/p>\n<p>Danach weisen wir die Referenzen auf das Steuer-element und das Hauptformular zu und f&uuml;gen die neue Instanz aus der Objektvariablen zur Collection <b>colControlWrappers <\/b>hinzu:<\/p>\n<pre>     For Each ctl In Me!sfm.Form.Controls\r\n         strControlSource = \"\"\r\n         On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n         strControlSource = ctl.ControlSource\r\n         <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strControlSource) = 0<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">Set<\/span> objControlWrapper = <span style=\"color:blue;\">New<\/span> clsControlWrapper\r\n             <span style=\"color:blue;\">With<\/span> objControlWrapper\r\n                 <span style=\"color:blue;\">Set<\/span> .Control = ctl\r\n                 <span style=\"color:blue;\">Set<\/span> .Form = Me\r\n             End <span style=\"color:blue;\">With<\/span>\r\n             colControlWrappers.Add objControlWrapper\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> ctl\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Auf diese Weise durchlaufen wir alle Steuer-elemente. Anschlie&szlig;end sollte, wenn man auf eines der Steuer-elemente im Unterformular klickt, eine der drei Ereignisprozeduren der zugeordneten Instanz der Klasse <b>clsControlWrapper <\/b>ausgel&ouml;st werden.<\/p>\n<h2>Die zu verschiebenden Eintr&auml;ge ermitteln<\/h2>\n<p>Wenn der Benutzer einen oder mehrere Eintr&auml;ge zum Verschieben ausgew&auml;hlt hat und auf eine der Schaltfl&auml;chen zum Verschieben klickt, wollen wir zun&auml;chst die Prim&auml;rschl&uuml;sselwerte der zu verschiebenden Eintr&auml;ge ermitteln. Das machen wir etwa in der Prozedur <b>cmdUp_Click<\/b>, indem wir eine Funktion namens <b>GetMove <\/b>aufrufen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdUp_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>lngMove()<span style=\"color:blue;\"> As Long<\/span>\r\n     lngMove = GetMove\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Diese Funktion soll wie folgt aussehen:<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>GetMove()<span style=\"color:blue;\"> As Long<\/span>()\r\n     <span style=\"color:blue;\">Dim <\/span>lngMove()<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> rst = m_SubForm.RecordsetClone\r\n     For i = m_SubForm.SelTop To m_SubForm.SelTop  + m_SubForm.SelHeight - 1\r\n         ReDim Preserve lngMove(k)\r\n         rst.AbsolutePosition = i - 1\r\n         lngMove(j) = rst(m_PKField)\r\n         j = j + 1\r\n     <span style=\"color:blue;\">Next<\/span> i\r\n     GetMove = lngMove\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Die Prozedur erstellt zun&auml;chst einen <b>RecordsetClone <\/b>vom Recordset des Formulars, also eine Kopie des dort verwendeten Recordsets. In diesem k&ouml;nnen wir nun navigieren, ohne dass wir die Position des Datensatzzeigers des Recordsets im Formular ver&auml;ndern. Um alle markierten Elemente zu durchlaufen, ermitteln wir in einer entsprechenden <b>For&#8230;Next<\/b>-Schleife den Index des ersten und letzten markierten Elements. Den Index des ersten erhalten wir mit der Eigenschaft <b>m_SubForm.SelTop <\/b>des Formulars, den Index des letzten mit <b>m_SubForm.SelTop + m_SubForm.SelHeight &#8211; 1<\/b>. Zumindest theoretisch. Wenn wir <b>GetMove <\/b>beim Anklicken der Schaltfl&auml;che aufrufen, erhalten wir zwar f&uuml;r <b>SelTop <\/b>den Index des ersten Eintrags der zuvor markierten Eintr&auml;ge. Allerdings liefert <b>SelHeight <\/b>immer den Wert <b>0<\/b>. Das Problem ist, dass wir mit dem Anklicken der Schaltfl&auml;che das Unterformular verlassen und damit auch die Markierung verloren geht (siehe Bild 8).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_04\/pic_1198_008.png\" alt=\"Bei Fokusverlust geht die Markierung verloren.\" width=\"474,6776\" height=\"255,4527\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Bei Fokusverlust geht die Markierung verloren.<\/span><\/b><\/p>\n<p>Wir m&uuml;ssen also die markierten Eintr&auml;ge bereits vor dem Aufheben der Markierung erfassen und im Array <b>lngMove() <\/b>speichern. Die passende Gelegenheit dazu ist das Ereignis <b>Beim Verlassen<\/b> des Unterformular-Steuer-elements. F&uuml;r dieses hinterlegen wir nun die folgende Prozedur:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>sfm_Exit(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>j<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> rst = m_SubForm.RecordsetClone\r\n     For i = m_SubForm.SelTop To m_SubForm.SelTop +  m_SubForm.SelHeight - 1\r\n         ReDim Preserve lngMove(j)\r\n         rst.AbsolutePosition = i - 1\r\n         lngMove(j) = rst(m_PKField)\r\n         j = j + 1\r\n     <span style=\"color:blue;\">Next<\/span> i\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Dadurch brauchen wir die Funktion <b>GetMove <\/b>nicht mehr. Daf&uuml;r m&uuml;ssen wir die Variable <b>lngMove <\/b>nun modulweit deklarieren, damit alle Routinen nach dem F&uuml;llen auf diese zugreifen k&ouml;nnen. Die Deklaration sieht wie folgt aus:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>lngMove()<span style=\"color:blue;\"> As Long<\/span><\/pre>\n<h2>Funktion der Schaltfl&auml;chen<\/h2>\n<p>Die Funktion der Schaltfl&auml;chen <b>cmdTop<\/b>, <b>cmdUp<\/b>, <b>cmdDown <\/b>und <b>cmdBottom <\/b>beim Anklicken haben wir bereits im Beitrag <b>Listenfeld: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern <\/b>(<b>www.access-im-unternehmen.de\/1197<\/b>) erl&auml;utert. Die Prozeduren in der L&ouml;sung des vorliegenden Beitrags entsprechen denen aus dem genannten Beitrag weitgehend. Lediglich die Deklaration der Variablen <b>lngMoves<\/b> sowie die Anweisung zum F&uuml;llen dieser Variablen fehlen in jeder der Prozeduren (siehe Listing 3).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdBottom_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>lngTarget<span style=\"color:blue;\"> As Long<\/span>\r\n     lngTarget = DMax(m_Orderfield, m_Table)\r\n     InterchangeOrder lngTarget, lngMove\r\n     RequeryControls lngMove\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>cmdDown_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>lngTarget<span style=\"color:blue;\"> As Long<\/span>, lngTargetMove<span style=\"color:blue;\"> As Long<\/span>, lngMax<span style=\"color:blue;\"> As Long<\/span>\r\n     lngMax = <span style=\"color:blue;\">UBound<\/span>(lngMove)\r\n     lngTargetMove = DLookup(m_Orderfield, m_Table, m_PKField & \"=\" & lngMove(lngMax))\r\n     lngTarget = DMin(m_Orderfield, m_Table, m_Orderfield & \"&gt;\" & lngTargetMove)\r\n     InterchangeOrder lngTarget, lngMove\r\n     RequeryControls lngMove\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>cmdTop_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>lngTarget<span style=\"color:blue;\"> As Long<\/span>\r\n     lngTarget = DMin(m_Orderfield, m_Table)\r\n     InterchangeOrder lngTarget, lngMove\r\n     RequeryControls lngMove\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>cmdUp_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>lngTarget<span style=\"color:blue;\"> As Long<\/span>, lngTargetMove<span style=\"color:blue;\"> As Long<\/span>\r\n     lngTargetMove = DLookup(m_Orderfield, m_Table, m_PKField & \"=\" & lngMove(0))\r\n     lngTarget = DMax(m_Orderfield, m_Table, m_Orderfield & \"&lt;\" & lngTargetMove)\r\n     InterchangeOrder lngTarget, lngMove\r\n     RequeryControls lngMove\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Die Ereignisse, die durch das Anklicken der Schaltfl&auml;chen ausgel&ouml;st werden<\/span><\/b><\/p>\n<p>Hier die Kurzfassung der Prozeduren:<\/p>\n<ul>\n<li>Die Prozedur <b>cmdBottom_Click<\/b> ermittelt den Datensatz mit dem gr&ouml;&szlig;ten Wert im Feld Reihenfolge als Ziel zum Verschieben der markierten Eintr&auml;ge und &uuml;bergibt diesen dann an die Prozeduren <b>InterchangeOrder <\/b>und <b>RequeryControls<\/b>. Dies verschiebt die markierten Datens&auml;tze an die Stelle des Datensatzes hinter dem letzten markierten Datensatz.<\/li>\n<li>Die Prozedur <b>cmdDown_Click <\/b>braucht ein paar Schritte mehr als die zuvor beschriebene. Sie ermittelt erst den Prim&auml;rschl&uuml;sselwert des letzten Elements aus <b>lngMove<\/b>, liest dazu die <b>ReihenfolgeID <\/b>ein und berechnet dann mit <b>DMin <\/b>die kleinste <b>ReihenfolgeID<\/b>, die gr&ouml;&szlig;er als die zuvor ermittelte ist. Damit geht es dann wieder in die Prozduren <b>InterchangeOrder <\/b>und <b>RequeryControls<\/b>.<\/li>\n<li>Die Prozedur <b>cmdTop_Click <\/b>ermittelt das Zielelement einfach als kleinstes Element der zugrundeliegenden Datenquelle.<\/li>\n<li>Die Prozedur <b>cmdUp_Click <\/b>ermittelt die <b>ReihenfolgeID <\/b>zum ersten Wert von <b>lngMove <\/b>und liest dann den kleinsten Wert des Feldes <b>ReihenfolgeID <\/b>ein, das noch gr&ouml;&szlig;er als die zuvor eingelesene <b>ReihenfolgeID <\/b>ist.<\/li>\n<\/ul>\n<h2>Prozedur zum Anpassen der Reihenfolge<\/h2>\n<p>Gegen&uuml;ber der L&ouml;sung im Beitrag <b>Listenfeld: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern <\/b>haben wir die Prozedur <b>InterchangeOrder<\/b> etwas angepasst.<\/p>\n<p>Die wichtigste &Auml;nderung ist ein codesparendes Refactoring, mit dem wir die kompletten Anweisungen zum Durchlaufen der zu &auml;ndernden Daten im Recordset in eine eigene Prozedur ausgelagert haben, die wir nun von vier Stellen der Prozedur <b>InterchangeOrder <\/b>aus aufrufen. Dadurch ist diese Prozedur um Einiges schlanker geworden (siehe Listing 4).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>InterchangeOrder(lngTargetOrderID<span style=\"color:blue;\"> As Long<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>strVerschieben<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strVerdraengen<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngTargetMove<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strIn<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>j<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngStartVerschieben<span style=\"color:blue;\"> As Long<\/span>\r\n     For i = <span style=\"color:blue;\">LBound<\/span>(lngMove) To <span style=\"color:blue;\">UBound<\/span>(lngMove)\r\n         strIn = strIn & \", \" & lngMove(i)\r\n     <span style=\"color:blue;\">Next<\/span> i\r\n     strIn = <span style=\"color:blue;\">Mid<\/span>(strIn, 3)\r\n     strIn = \" IN (\" & strIn & \")\"\r\n     lngTargetMove = DLookup(m_Orderfield, m_Table, m_PKField & \" = \" & lngMove(0))\r\n     <span style=\"color:blue;\">If <\/span>lngTargetOrderID &lt; lngTargetMove<span style=\"color:blue;\"> Then<\/span>\r\n         strVerschieben = \"SELECT * FROM \" & m_Table & \" WHERE \" & m_PKField & strIn & \" ORDER BY \" & m_Orderfield\r\n         j = lngTargetOrderID\r\n         Verschieben strVerschieben, j\r\n         strVerdraengen = \"SELECT * FROM \" & m_Table & \" WHERE \" & m_PKField & \" NOT\" & strIn & \" AND \" _\r\n             & m_Orderfield & \" &gt;= \" & lngTargetOrderID & \" ORDER BY \" & m_Orderfield\r\n         Verschieben strVerdraengen, j\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         lngStartVerschieben = DLookup(m_Orderfield, m_Table, m_PKField & \"=\" & lngMove(0))\r\n         strVerdraengen = \"SELECT * FROM \" & m_Table & \" WHERE \" & m_PKField & \" NOT\" & strIn & \" AND \" _\r\n             & m_Orderfield & \" &gt; \" & lngStartVerschieben & \" AND \" & m_Orderfield & \" &lt;= \" & lngTargetOrderID _\r\n             & \" ORDER BY \" & m_Orderfield\r\n         j = DLookup(m_Orderfield, m_Table, m_PKField & \"=\" & lngMove(0))\r\n         Verschieben strVerdraengen, j\r\n         strVerschieben = \"SELECT * FROM \" & m_Table & \" WHERE \" & m_PKField & strIn & \" ORDER BY \" & m_Orderfield\r\n         Verschieben strVerschieben, j\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: Die Prozedur zum &Auml;ndern der Reihenfolge von Elementen<\/span><\/b><\/p>\n<p>Der grundlegende Aufbau der Prozedur ist indes der gleiche wie im oben genannten Beitrag. Sie nimmt die <b>ReihenfolgeID <\/b>entgegen, an deren Stelle die verschobenen Elemente eingesetzt werden sollen.<\/p>\n<p><b>lngMove <\/b>brauchen wir hier nicht mehr als Parameter zu &uuml;bergeben, da wir die Variable ja als modulweit g&uuml;ltig deklariert haben. Die Prozedur erstellt in einer <b>For&#8230;Next<\/b>-Schleife aus den Elementen von <b>lngMove <\/b>eine kommaseparierte Liste.<\/p>\n<p>Die folgende <b>If&#8230;Then<\/b>-Bedingung k&uuml;mmert sich im <b>If<\/b>-Teil um das Verschieben nach oben und im <b>Else<\/b>-Teil um das Verschieben nach unten.<\/p>\n<p>Der <b>If<\/b>-Teil stellt erst eine <b>SELECT<\/b>-Anweisung mit den zu verschiebenden Elementen zusammen und &uuml;bergibt diese an die Prozedur <b>Verschieben<\/b>, welche die Datens&auml;tze durchl&auml;uft und die Werte des Feldes <b>ReihenfolgeID <\/b>entsprechend &auml;ndert. Danach folgt eine SQL-Anweisung mit den durch die verschobenen Elemente verdr&auml;ngten Elemente.<\/p>\n<p>Im <b>Else<\/b>-Teil l&auml;uft es andersherum &#8211; hier werden erst die verdr&auml;ngten Elemente in einer <b>SELECT<\/b>-Anweisung zusammengestellt und ihre Reihenfolge in der Prozedur <b>Verschieben <\/b>bearbeitet und erst dann die verschobenen Elemente.<\/p>\n<h2>Die Prozedur &#8222;Verschieben&#8220;<\/h2>\n<p>Die von der Prozedur <b>InterchangeOrder <\/b>aufgerufene Prozedur <b>Verschieben <\/b>nimmt mit <b>strSQL <\/b>die <b>SELECT<\/b>-Anweisung sowie mit <b>j <\/b>die aktuell zuzuweisende <b>ReihenfolgeID <\/b>entgegen (siehe Listing 5). Sie erstellt ein Recordset auf Basis von <b>strSQL <\/b>und durchl&auml;uft die Datens&auml;tze, wobei sie dem ersten f&uuml;r das Feld <b>ReihenfolgeID <\/b>den &uuml;bergebenen Wert aus dem Parameter <b>j <\/b>zuweist. <b>j <\/b>wird dann mit jedem Durchlauf der <b>Do While<\/b>-Schleife &uuml;ber alle Datens&auml;tze des Recordsets um <b>1 <\/b>erh&ouml;ht. Damit ist das Verschieben der Reihenfolge erledigt, und durch die <b>Requery<\/b>-Methode in der Prozedur <b>RequeryControls <\/b>wird die richtige Reihenfolge auch direkt im Datenblatt angezeigt. Allein die vorherige Markierung der verschobenen Datens&auml;tze m&uuml;ssen wir noch wiederherstellen.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Verschieben(strSQL<span style=\"color:blue;\"> As String<\/span>, <span style=\"color:blue;\">Optional<\/span> j<span style=\"color:blue;\"> As Integer<\/span>)\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(strSQL, dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         rst.Edit\r\n         rst(m_Orderfield) = j\r\n         rst.Update\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n         j = j + 1\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: &Auml;ndern der Reihenfolge der einzelnen Elemente<\/span><\/b><\/p>\n<p>Das erledigen wir in der ebenfalls durch <b>RequeryControls <\/b>aufgerufene Prozedur <b>Select-Entries<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>RequeryControls()\r\n     m_SubForm.Requery\r\n     SelectEntries\r\n     ActivateControls\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Markierung wiederherstellen<\/h2>\n<p>Nun folgt eine weitere interessante Aufgabe: Das Wiederherstellen der Markierung, also das Selektieren der Eintr&auml;ge, die vor dem Anklicken einer der Schaltfl&auml;chen <b>cmdTop<\/b>, <b>cmdUp<\/b>, <b>cmdDown <\/b>oder <b>cmdBottom <\/b>markiert waren. Das ist n&ouml;tig, da durch das Requery des Unterformulars zum Anordnen der Elemente in der neuen Reihenfolge die Markierungen aufgehoben werden. Und nicht nur dadurch: Auch durch das Verlassen des Unterformular-Steuerelements geht die Markierung bereits verloren.<\/p>\n<p>Das bringt zus&auml;tzlich mit sich, dass wir nicht nur die Markierung wiederherstellen, sondern nach dem Anklicken einer der vier genannten Schaltfl&auml;chen auch noch den Fokus zum Unterformular zur&uuml;ckverschieben m&uuml;ssen. Anderenfalls k&ouml;nnen wir darin soviele Eintr&auml;ge markieren, wie wir wollen &#8211; die Markierung wird schlicht nicht angezeigt. Und es gibt noch einen weiteren Trick den Sie gleich kennenlernen. Das Wiederherstellen der Markierung nimmt die Prozedur <b>SelectEntries <\/b>vor. Diese nutzt wiederum das Array <b>lngMove <\/b>mit den beim Anklicken einer der Schaltfl&auml;chen markierten Elemente. Doch zun&auml;chst deklariert die Prozedur einige Variablen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>SelectEntries()\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>lngTop<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngHeight<span style=\"color:blue;\"> As Long<\/span><\/pre>\n<p>Danach verschiebt sie den Fokus wieder auf das Unterformular-Steuerelement. Dann erstellt sie ein <b>RecordsetClone <\/b>vom Recordset des Unterformulars und speichert den Prim&auml;rschl&uuml;sselwert des ersten markierten Eintrags in der Variablen <b>lngTop<\/b>:<\/p>\n<pre>     Me!sfm.SetFocus\r\n     <span style=\"color:blue;\">Set<\/span> rst = m_SubForm.RecordsetClone\r\n     lngTop = lngMove(0)<\/pre>\n<p>Danach sucht sie das zu <b>lngTop <\/b>passende Element aus dem <b>RecordsetClone<\/b>:<\/p>\n<pre>     rst.FindFirst m_PKField & \"=\" & lngTop<\/pre>\n<p>Nun kommt der Trick: Bevor wir die Markierung durch Einstellen der beiden Eigenschaften <b>SelTop <\/b>und <b>SelHeight <\/b>wiederherstellen, sorgen wir mit dem folgenden Befehl daf&uuml;r, dass der aktuell markierte Datensatz komplett markiert wird &#8211; also so, als ob der Benutzer auf den Datensatzmarkierer klickt:<\/p>\n<pre>     RunCommand acCmdSelectAllRecords<\/pre>\n<p>Dann stellen wir mit <b>SelTop <\/b>und <b>SelHeight <\/b>den zu markierenden Bereich ein. <b>SelTop <\/b>nimmt den Wert der Eigenschaft <b>AbsolutePosition <\/b>des im <b>RecordsetClone <\/b>als ersten markierten Eintrag identifizierten Datensatz plus eins an:<\/p>\n<pre>     m_SubForm.SelTop = rst.AbsolutePosition + 1<\/pre>\n<p>Und f&uuml;r <b>SelHeight <\/b>ermitteln wir die Anzahl der Datens&auml;tze &uuml;ber die Anzahl der Eintr&auml;ge im Array <b>lngMove<\/b>:<\/p>\n<pre>     m_SubForm.SelHeight = <span style=\"color:blue;\">UBound<\/span>(lngMove) - <span style=\"color:blue;\">LBound<\/span>(lngMove) + 1\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Damit erreichen wir nach dem Verschieben die Markierung der zuvor markierten Datens&auml;tze.<\/p>\n<h2>Sortierung muss beibehalten werden<\/h2>\n<p>Zum Schluss ist noch zu beachten, dass die Schaltfl&auml;chen nur wie gew&uuml;nscht arbeiten, wenn der Benutzer die Sortierung des Formulars in der Datenblattansicht nicht &auml;ndert. Anderenfalls treten beim Versuch, die Daten dennoch zu sortieren, fr&uuml;her oder sp&auml;ter Fehlermeldungen auf.<\/p>\n<p>Wie Sie dies verhindern, lesen Sie im Beitrag <b>Datenblatt-Funktionen einschr&auml;nken <\/b>(<b>www.access-im-unternehmen.de\/1201<\/b>).<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>ReihenfolgeMehrereEintraege.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/1A8D1FF1-F5EC-402B-A88D-064A8D9C82BD\/aiu_1198.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wir haben bereits in mehreren Beitr&auml;gen beschrieben, wie Sie die individuelle Reihenfolge von Elementen einer Tabelle &uuml;ber den Inhalt eines Feldes etwa namens &#8222;ReihenfolgeID&#8220; einstellen k&ouml;nnen &#8211; zum Beispiel in Listenfeldern oder Unterformularen in der Datenblattansicht. Dort haben wir die Reihenfolge dann durch Markieren der Eintr&auml;ge und anschlie&szlig;endes Bet&auml;tigen etwa von Schaltfl&auml;chen mit Beschriftungen wie &#8222;Ganz nach oben&#8220;, &#8222;Nach oben&#8220;, &#8222;Nach unten&#8220; oder &#8222;Ganz nach unten&#8220; ge&auml;ndert. Im vorliegenden Beitrag schauen wir uns nun an, wie wir im Unterformular in der Datenblattansicht die Reihenfolge f&uuml;r mehrere Eintr&auml;ge gleichzeitig &auml;ndern k&ouml;nnen.<\/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":[662019,66042019,44000023],"tags":[],"class_list":["post-55001198","post","type-post","status-publish","format-standard","hentry","category-662019","category-66042019","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>Datenblatt: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern - 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\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Datenblatt: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern\" \/>\n<meta property=\"og:description\" content=\"Wir haben bereits in mehreren Beitr&auml;gen beschrieben, wie Sie die individuelle Reihenfolge von Elementen einer Tabelle &uuml;ber den Inhalt eines Feldes etwa namens &quot;ReihenfolgeID&quot; einstellen k&ouml;nnen - zum Beispiel in Listenfeldern oder Unterformularen in der Datenblattansicht. Dort haben wir die Reihenfolge dann durch Markieren der Eintr&auml;ge und anschlie&szlig;endes Bet&auml;tigen etwa von Schaltfl&auml;chen mit Beschriftungen wie &quot;Ganz nach oben&quot;, &quot;Nach oben&quot;, &quot;Nach unten&quot; oder &quot;Ganz nach unten&quot; ge&auml;ndert. Im vorliegenden Beitrag schauen wir uns nun an, wie wir im Unterformular in der Datenblattansicht die Reihenfolge f&uuml;r mehrere Eintr&auml;ge gleichzeitig &auml;ndern k&ouml;nnen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-13T20:55:43+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg06.met.vgwort.de\/na\/0373440d9a5f477393d729c6528efd4c\" \/>\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=\"28\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Datenblatt: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern\",\"datePublished\":\"2020-05-13T20:55:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/\"},\"wordCount\":4511,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/0373440d9a5f477393d729c6528efd4c\",\"articleSection\":[\"2019\",\"4\\\/2019\",\"Mit Formularen arbeiten\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/\",\"name\":\"Datenblatt: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/0373440d9a5f477393d729c6528efd4c\",\"datePublished\":\"2020-05-13T20:55:43+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/0373440d9a5f477393d729c6528efd4c\",\"contentUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/0373440d9a5f477393d729c6528efd4c\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Datenblatt: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern\"}]},{\"@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":"Datenblatt: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern - 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\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/","og_locale":"de_DE","og_type":"article","og_title":"Datenblatt: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern","og_description":"Wir haben bereits in mehreren Beitr&auml;gen beschrieben, wie Sie die individuelle Reihenfolge von Elementen einer Tabelle &uuml;ber den Inhalt eines Feldes etwa namens \"ReihenfolgeID\" einstellen k&ouml;nnen - zum Beispiel in Listenfeldern oder Unterformularen in der Datenblattansicht. Dort haben wir die Reihenfolge dann durch Markieren der Eintr&auml;ge und anschlie&szlig;endes Bet&auml;tigen etwa von Schaltfl&auml;chen mit Beschriftungen wie \"Ganz nach oben\", \"Nach oben\", \"Nach unten\" oder \"Ganz nach unten\" ge&auml;ndert. Im vorliegenden Beitrag schauen wir uns nun an, wie wir im Unterformular in der Datenblattansicht die Reihenfolge f&uuml;r mehrere Eintr&auml;ge gleichzeitig &auml;ndern k&ouml;nnen.","og_url":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-13T20:55:43+00:00","og_image":[{"url":"http:\/\/vg06.met.vgwort.de\/na\/0373440d9a5f477393d729c6528efd4c","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"28\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Datenblatt: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern","datePublished":"2020-05-13T20:55:43+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/"},"wordCount":4511,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/0373440d9a5f477393d729c6528efd4c","articleSection":["2019","4\/2019","Mit Formularen arbeiten"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/","url":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/","name":"Datenblatt: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/0373440d9a5f477393d729c6528efd4c","datePublished":"2020-05-13T20:55:43+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/#primaryimage","url":"http:\/\/vg06.met.vgwort.de\/na\/0373440d9a5f477393d729c6528efd4c","contentUrl":"http:\/\/vg06.met.vgwort.de\/na\/0373440d9a5f477393d729c6528efd4c"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Datenblatt_Reihenfolge_mehrerer_Eintraege_aendern\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Datenblatt: Reihenfolge mehrerer Eintr&auml;ge &auml;ndern"}]},{"@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\/55001198","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=55001198"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001198\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001198"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001198"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001198"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}