Drag and Drop mit ListBox-Elementen

Wenn Sie ein Abonnement des Magazins 'DATENBANKENTWICKLER' besitzen, können Sie sich anmelden und den kompletten Artikel lesen.
Anderenfalls können Sie das Abonnement hier im Shop erwerben.

Drag and Drop mit ListBox-Elementen

Im Artikel Drag and Drop-Grundlagen haben wir uns die grundlegenden Techniken für die Implementierung von Drag and Drop-Funktionen in WPF-Benutzeroberflächen angesehen. Nun gehen wir einen Schritt weiter und wollen Drag and Drop für das Fenster namens Versendungen unserer Beispielanwendung Bestellverwaltung umsetzen. Hier geht es dann nicht nur um einfaches Bewegen von Elementen per Maus, sondern auch um die Anpassung der dahinter stehenden Daten beziehungsweise Tabellen.

Wozu braucht man aber Drag and Drop so dringend? In der Tat lassen sich die meisten Tätigkeiten, die Sie damit ausführen können, auch auf andere Weise realisieren. Allerdings ist Drag and Drop und somit das einfache Ziehen von Elementen der Benutzeroberfläche mit der Maus doch ein sehr intuitiver Weg, um Aktionen durchzuführen. Ein Beispiel sind die beiden Listenfelder aus dem Artikel m:n-Beziehung mit Listenfeld (siehe Bild 1). Im Artikel haben wir Schaltflächen bereitgestellt, mit denen ein oder alle Artikel von einem Listenfeld zum anderen übertragen werden können. Nun wollen wir uns weiter vortasten und Drag and Drop-Funktionalität zu diesem Fenster hinzufügen. Zuvor schauen wir uns das jedoch an einigen grundlegenden Beispielen an.

Drag and Drop mit Listenfeldern

Nun schauen wir uns an, wie wir Drag and Drop in unser Beispiel mit den Versendungen einbauen. In der Beispielanwendung Bestellverwaltung_SQLite fügen wir dazu eine neue Window-Klasse namens Versendungen_DragDrop hinzu und kopieren den XAML-Code der Klasse Versendungen dort hinein. Passen Sie danach das Window-Element so an, dass die Klasse Bestellverwaltung.Versendungen_DragDrop referenziert wird und der Titel des Fensters angepasst ist:

<Window x:Class="Bestellverwaltung.Versendungen_DragDrop"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:local="clr-namespace:Bestellverwaltung"
         mc:Ignorable="d"
         Title="Versendungen Drag and Drop" Height="300" Width="400">

Dann kopieren Sie auch den Code der Code behind-Klasse von Versendungen.xaml.cs in Versendungen_DragDrop.xaml.cs. Ändern Sie hier zunächst in der folgenden Zeile Versendungen in Versendungen_DragDrop:

public partial class Versendungen_DragDrop : Window, INotifyPropertyChanged {

Der gleiche Schritt ist auch nochmal in der ersten Zeile der Konstruktor-Methode nötig:

public Versendungen_DragDrop() {

Danach können wir die Funktionen für das Drag and Drop hinzufügen.

Drag and Drop-Vorgang starten

Wir beginnen mit dem linken ListBox-Element. Hier legen wir gar nicht erst die Methode für das Ereignis MouseDown an, von dem wir dank der Experimente im Artikel Drag and Drop-Grundlagen schon wissen, dass es nicht feuert. Stattdessen legen wir direkt das entsprechende Tunneling-Ereignis PreviewMouseDown an:

<ListBox x:Name="lstAusgewaehlteKunden" Grid.Column="0" Grid.Row="1" Margin="5"
     ItemsSource="{Binding AusgewaehlteKunden}"
     DisplayMemberPath="Nachname"
     SelectedValuePath="ID" MouseDoubleClick="lstAusgewaehlteKunden_MouseDoubleClick" PreviewMouseDown="lstAusgewaehlteKunden_PreviewMouseDown"/>

Dafür hinterlegen wir nun die folgende Ereignismethode:

private void lstAusgewaehlteKunden_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
     if (e.LeftButton == MouseButtonState.Pressed) {
         DragDrop.DoDragDrop(lstAusgewaehlteKunden, lstAusgewaehlteKunden.SelectedItem, DragDropEffects.Copy);
     }
}

Wenn wir die Anwendung nun starten, das Fenster Versendungen_DragDrop aufrufen und einen der Einträge der linken List­Box ziehen wollen, erhalten wir den Fehler aus Bild 2.

Fehler beim Versuch, ein Element aus der linken ListBox zu ziehen

Bild 1: Fehler beim Versuch, ein Element aus der linken ListBox zu ziehen

Da der Fehler nicht direkt an Ort und Stelle gemeldet wird, müssen wir eine Fehlerbehandlung hinzufügen:

private void lstAusgewaehlteKunden_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
     try {
         if (e.LeftButton == MouseButtonState.Pressed) {
             DragDrop.DoDragDrop(lstAusgewaehlteKunden, lstAusgewaehlteKunden.SelectedItem, DragDropEffects.Copy);
         }
     }
     catch (System.Exception ex) {
         MessageBox.Show(ex.Message);
         throw;
     }
}

Dies liefert dann die Meldung aus Bild 3. Offensichtlich versuchen wir auf irgendeine Weise, ein Element des Typs Null zu ziehen. Welches das ist, erfahren wir per Debugging.

Der gleiche Fehler, diesmal mit Fehlerbehandlung

Bild 2: Der gleiche Fehler, diesmal mit Fehlerbehandlung

Dazu setzen wir einen Haltepunkt in der ersten Zeile der Methode lstAusgewaehlteKunden_PreviewMouseDown und schauen uns den Inhalt der Parameter der Methode DragDrop.DoDragDrop an. Hier erfahren wir, dass die SelectedItem-Eigenschaft des ListBox-Elements den Wert null liefert (siehe Bild 4).

Debugging der fehlerhaften Stelle

Bild 3: Debugging der fehlerhaften Stelle

Wir müssen also offensichtlich einen ganz anderen Weg wählen, um beim Herunterdrücken der Maustaste Zugriff auf das dabei überfahrene Element zu bekommen. Dabei nutzen wir eine kleine Hilfsklasse, um das zu verschiebende Element zwischenzuspeichern:

public class DragDropData {
     public object ActualData { get; set; }
}

Dieses soll in der Eigenschaft ActualData das zu verschiebende Element speichern. Die Ereignismethode lstAusgewaehlteKunden_PreviewMouseDown ändern wir wie folgt ab:

private void lstAusgewaehlteKunden_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
     try {
         if (e.LeftButton == MouseButtonState.Pressed) {
             var item = (ListBoxItem)ItemsControl.ContainerFromElement(lst, (DependencyObject)e.OriginalSource);
             Kunde kunde = (Kunde)item.Content;
             DragDropData dragDropData = new DragDropData
             {
                 ActualData = kunde,
             };
             DragDrop.DoDragDrop(lst, dragDropData, DragDropEffects.Move);
         }
     }
     catch (System.Exception ex) {
         MessageBox.Show(ex.Message);
         throw;
     }

Dies war die Leseprobe dieses Artikels.
Melden Sie sich an, um auf den vollständigen Artikel zuzugreifen.

Bitte geben Sie die Zeichenfolge in das nachfolgende Textfeld ein

Die mit einem * markierten Felder sind Pflichtfelder.

Ich habe die Datenschutzbestimmungen zur Kenntnis genommen.