Drag and Drop mit dem ListView-Steuerelement

Zusammenfassung

Erfahren Sie, wie Sie mit Drag and Drop im ListView m:n-Beziehungen verwalten und individuelle Reihenfolgen anpassen können.

Techniken

ListView-Steuerelement, VBA

Voraussetzungen

Access 2000 und höher

Beispieldateien

ListView.mdb, MSCOMCTL.msi

André Minhorst, Duisburg

Listenfelder sind eine schöne Einrichtung. Wie schade, dass sie kein Drag and Drop erlauben. Aber vielleicht haben Sie Glück und setzen Access 2002 oder höher ein oder besitzen ein passendes Entwicklerpaket: Dann können Sie nämlich das ListView-Steuerelement verwenden und mit diesem die gewünschte Drag and Drop-Funktion realisieren.

Beispiele für zwei Listenfelder, zwischen denen Daten hin und her verschoben werden sollen, gibt es wie Sand am Meer. Oft handelt es sich dabei um die Abbildung von m:n-Beziehungen. Warum also nicht mal wieder das gute alte Verteiler-Beispiel aufgreifen Hier geht es darum, für eine Publikation eine Reihe Empfänger aus den vorhandenen Kontakten auszuwählen.

Das Beispiel basiert auf drei Tabellen: Die Tabelle tblPublikationen enthält die zu veröffentlichenden Werke, die Tabelle tblEmpfaenger die Adressen und die Tabelle tblVerteiler verknüpft die Einträge der einen mit denen der anderen Tabelle. Im Beziehungsfenster sieht das wie in Abb. 1 aus.

Abb. 1: Datenmodell der Beispieldatenbank

Das Formular soll in zwei ListView-Steuerelementen die Empfänger und die Nicht-Empfänger der Publikation anzeigen (s. Abb. 2).

Abb. 2: So soll das Formular zum Hin- und Herschieben von Empfängern aussehen.

Quellcode 1: Diese Routine füllt eine Liste mit den Daten einer Tabelle

Private Sub ListeAktualisieren(objListView As ListView, strSQL As String)
    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Set db = CurrentDb
    Set rst = db.OpenRecordset(strSQL, dbOpenDynaset)
    objListView.ListItems.Clear
    Do While Not rst.EOF
        objListView.ListItems.Add , "a" & rst(0), rst(1)
        rst.MoveNext
    Loop
    rst.Close
    Set rst = Nothing
    Set db = Nothing
End Sub

Quellcode 2: Aufruf der Routine zum Füllen der beiden ListView-Steuerelemente

Private Sub Form_Current()
    Dim strSQLEmpfaenger As String
    Dim strSQLKeinEmpfaenger As String
    If Not IsNull(Me.Publikation) Then
        strSQLEmpfaenger = "SELECT tblEmpfaenger.EmpfaengerID, tblEmpfaenger.Empfaenger " _            & "FROM tblEmpfaenger INNER JOIN tblVerteiler ON tblEmpfaenger.EmpfaengerID = " _            & " tblVerteiler.EmpfaengerID WHERE tblVerteiler.PublikationID = " _            & Me.PublikationID & " ORDER BY tblEmpfaenger.Empfaenger"
        strSQLKeinEmpfaenger = "SELECT tblEmpfaenger.EmpfaengerID, tblEmpfaenger.Empfaenger " _            & "FROM tblEmpfaenger WHERE tblEmpfaenger.EmpfaengerID NOT IN " _            & "(SELECT tblEmpfaenger.EmpfaengerID FROM tblEmpfaenger INNER JOIN tblVerteiler " _            & "ON tblEmpfaenger.EmpfaengerID = tblVerteiler.EmpfaengerID WHERE " _            & " tblVerteiler.PublikationID = " & Me.PublikationID _            & ") ORDER BY tblEmpfaenger.Empfaenger"
        ListeAktualisieren Me.lvwZugeordnet.Object, strSQLEmpfaenger
        ListeAktualisieren Me.lvwNichtZugeordnet.Object, strSQLKeinEmpfaenger
    End If
End Sub

Bevor überhaupt irgendein Eintrag von links nach rechts und umgekehrt gezogen werden kann, müssen erst einmal überhaupt Einträge da sein – dementsprechend folgt nun die Beschreibung des Aufbaus des Formulars.

Das Formular selbst ist an die Tabelle tblPublikationen gebunden. Bei jedem Wechsel des im Formular angezeigten Publikations-Datensatzes sollen auch die beiden ListViews aktualisiert werden. Die Routine wird daher logischerweise durch die Ereigniseigenschaft Beim Anzeigen aufgerufen.

Die beiden ListViews sind fast identisch aufgebaut, was sich auch auf das Füllen mit Daten auswirkt: Die dazu benötigte Routine sieht für beide Steuerelemente fast identisch aus. So identisch, dass man daraus eine einzige parametrisierte Routine machen kann. Als Parameter übergibt die aufrufende Prozedur nur einen Verweis auf das jeweilige Listenfeld sowie den SQL-Ausdruck, der die einzufügenden Datensätze festlegt.

Die Routine ListeAktualisieren ist für das Anlegen der Elemente der ListViews verantwortlich (s. Quellcode 1). Sie öffnet eine auf der übergebenen SQL-Anweisung basierende Datensatzgruppe und durchläuft diese. Dabei fügt sie je Datensatz ein Element zum angegebenen ListView hinzu. Das erste im SQL-Ausdruck angegebene Feld dient als Teil der Key-Eigenschaft des Elements, das zweite als angezeigter Text. Die beim Anzeigen des aktuellen Datensatzes im Formular ausgelöste Prozedur Form_Current ruft diese Routine zweimal mit verschiedenen Parametern auf (s. Quellcode 2).

Der erste dabei verwendete SQL-Ausdruck ermittelt alle Datensätze der verknüpften Tabellen tblEmpfaenger und tblVerteiler, bei denen die in der Tabelle tblVerteiler angegebene PublikationID mit der aktuell im Formular angezeigten übereinstimmt.

Quellcode 3: Der Drag-and-Drop-Vorgang startet im ListView lvwNichtZugeordnet …

Private Sub lvwNichtZugeordnet_OLEStartDrag(Data As Object, AllowedEffects As Long)
    Dim objListItem As ListItem
    Dim strData As String
    Dim strDataItems() As String
    For Each objListItem In lvwNichtZugeordnet.ListItems
        If objListItem.Selected = True Then
            strData = strData & objListItem.Key & "¦" & objListItem.Text & ";"
        End If
    Next
    Data.Clear
    Data.SetData strData, ccCFText
End Sub

Die zweite SQL-Anweisung verwendet fast die gleiche Anweisung wie die erste – allerdings nur als Unterabfrage. Damit ermittelt diese Abfrage alle Empfänger-Datensätze, die nicht durch die erste SQL-Anweisung erfasst werden und dementsprechend nicht über die Tabelle tblVerteiler mit der aktuell angezeigten Publikation verknüpft sind.

Aufbau der ListView-Steuerelemente

Die beiden ListViews sind genau gleich aufgebaut. Die einzigen Unterschiede sind der Name und die angezeigte Spaltenüberschrift. Die Eigenschaften im Detail:

  • Name: lvwEmpfaenger beziehungsweise lvwKeinEmpfaenger
  • View: 3 – lvwReport
  • Spaltenköpfe: je einer mit einer Breite von 2500 und der Beschriftung Empfänger beziehungsweise Kein Empfänger
  • MultiSelect: aktiviert
  • OLEDragMode: 1 – ccOLEDragAutomatic
  • OLEDropMode: 1 – ccOLEDropManual
  • Mit diesen Einstellungen und den beiden beschriebenen Routinen können Sie nun bereits die Daten aus den drei Tabellen darstellen. Es fehlt also nur noch die Drag-and-Drop-Funktion …

    Beim Drag and Drop mit ungebundenen Steuerelementen, wie es die ListViews nun einmal sind, ist vor allem eines zu beachten: Neben dem Verschieben des Eintrags zwischen den Listen müssen auch die dahinter liegenden Datenbanktabellen aktualisiert werden. Für das Ziehen eines Eintrags von einem zum anderen ListView benötigen Sie nur zwei Ereignisprozeduren – vorausgesetzt, Sie verzichten auf jeglichen Schnickschnack:

  • OLEStartDrag beim Quell-ListView
  • OLEDragDrop beim Ziel-ListView
  • Sie haben das Ende des frei verfügbaren Textes erreicht. Möchten Sie ...

    Workplace

    Jahresabonnement TestzugangOder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

    Schreibe einen Kommentar