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.
Basics: ObservableCollection
Unter WPF gibt es einige Mechanismen, welche die Bindung der Steuerelemente an die zugrunde liegenden Daten in einem gewissen Rahmen automatisieren. Diese werden durch die Programmierung bestimmt – entweder durch die Verwendung bestimmter Schnittstellen für Eigenschaften oder auch durch entsprechende Auflistungstypen, die dann als Datenquelle etwa für Listen-Elemente verwendet werden. Mit der PropertyChanged-Schnittstelle haben wir schon die Synchronisierung zwischen den Attributen der XAML-Definition und Eigenschaften in den Code-Klassen besprochen (siehe Artikel »Basics: PropertyChanged«). In diesem Artikel schauen wir uns nun den Auflistungstyp ObservableCollection an.
Beispielanwendung
Die Beispielanwendung verwendet die auch in den anderen Artikeln genutzte SQLite-Datenbank Bestellverwaltung.db. Wir wollen daraus die Tabelle Kunden nutzen, um die Unterschiede zwischen einer normalen Liste (List) und einer ObservableCollection zu demonstrieren.
Die ObservableCollection-Klasse ist eine Alternative beispielsweise zur List-Klasse. Der wesentliche Unterschied ist, dass die ObservableCollection-Klasse externe Objekte, die den Inhalt einer ObservableCollection anzeigen, über Änderungen informiert.
Änderungen können dabei etwa das Hinzufügen oder Entfernen von Elementen sein. Beispiele für Steuerelemente, die Sie an Objekte auf Basis der Klasse ObservableCollection binden können, sind etwa das ListBox-Element oder das DataGrid-Element.
Was aber heißt überhaupt »informieren« in diesem Zusammenhang? Wenn Sie etwa unter Access ein Listenfeld an eine Tabelle gebunden und dann einen Datensatz dieser Tabelle gelöscht haben, wurde der Datensatz nach dem Aufruf der Requery-Methode des Listenfeldes auch aus dem Listenfeld entfernt. In einem Formular in der Datenblattansicht führte das Löschen eines Datensatzes direkt zum Entfernen dieses Eintrags aus der Ansicht – sehr praktisch, aber auch logisch, da hier direkt die Tabelle an das Formular gebunden war. Unter WPF ist das alles etwas anders – hier binden Sie ja beispielsweise nicht direkt an Tabellen oder Abfragen, sondern an Auflistungen wie das List-Objekt, Collection oder ObservableCollection, die Sie zuvor noch mit den Daten aus der Datenbank füllen. Wenn Sie nun Änderungen an einem List- oder Collection-Objekt durchführen, wie es etwa geschieht, wenn Sie etwa einen neuen Eintrag hinzufügen oder einen Eintrag löschen, dann wirken sich die Änderungen zwar auf die Einträge des List- oder Collection-Objekts aus, aber sie schlagen sich nicht in der Benutzeroberfläche nieder.
Und hier tritt das ObservableCollection-Objekt auf den Plan: Wenn Sie diesem einen neuen Eintrag hinzufügen oder einen Eintrag entfernen, löst dies ein Ereignis aus, das automatisch von bestimmten Elementen der Benutzeroberfläche wie etwa dem ListBox- oder dem DataGrid-Element implementiert wird und dafür sorgt, dass die Ansicht aktualisiert wird. Um uns dies einmal an einem Beispiel anzusehen, haben wir das Fenster aus Bild 1 erstellt.
Bild 1: Beispiel für an ein List- und ein ObservableCollection-Objekt gebundene DataGrid-Steuerelemente
Die Definition dieser Steuerelemente finden Sie in Listing 1. Das erste DataGrid namens dgList ist an das Objekt KundenList der Code behind-Klasse gebunden, das zweite DataGrid namens dgObservableCollection an das Objekt KundenObservableCollection. Zu jedem DataGrid-Steuerelement haben wir jeweils eine Hinzufügen- und eine Entfernen-Schaltfläche hinzugefügt, mit denen Sie per Code jeweils einen neuen Datensatz anlegen beziehungsweise den aktuell markierten Datensatz aus dem zugrunde liegenden Auflistungsobjekt entfernen. Wir werden dann später erkennen, wo die Unterschiede zwischen dem List- und dem ObservableCollection-Objekt liegen.
<Window x:Class="ObservableCollection.MainWindow" ... Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<DataGrid x:Name="dgList" Grid.Column="0" Margin="5" ItemsSource="{Binding KundenList}"></DataGrid>
<DataGrid x:Name="dgObservableCollection" Margin="5" Grid.Column="1"
ItemsSource="{Binding KundenObservableCollection}"></DataGrid>
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal">
<Button x:Name="btnListAdd" Margin="5" Click="btnListAdd_Click">Add</Button>
<Button x:Name="btnListDelete" Margin="5" Click="btnListDelete_Click">Delete</Button>
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
<Button x:Name="btnObservableCollectionAdd" Margin="5" Click="btnObservableCollectionAdd_Click">Add</Button>
<Button x:Name="btnObservableCollectionDelete" Margin="5"
Click="btnObservableCollectionDelete_Click">Delete</Button>
</StackPanel>
</Grid>
</Window>
Listing 1: Definition der beiden DataGrid-Elemente und der Schaltflächen zum Hinzufügen und Löschen der Elemente
DataGrid-Elemente füllen
Damit die beiden DataGrid-Elemente gefüllt werden, haben wir der Code behind-Klasse etwas Code hinzugefügt. Im allgemeinen Teil haben wir dazu zunächst eine Objektvariable für den Datenbankkontext deklariert:
BestellverwaltungEntities dbContext;
Dann benötigen wir ein List-Objekt namens kundenList, das Elemente des Typs Kunde aufnehmen soll und über die öffentliche Eigenschaft KundenList per get und set verfügbar gemacht wird:
private List<Kunde> kundenList;
public List<Kunde> KundenList {
get {
return kundenList;
}
set {
kundenList = value;
}
}
Das Gleiche haben wir für ein Auflistungs-Element des Typs ObservableCollection durchgeführt. Dieses heißt allerdings kundenObservableCollection und wird wie folgt definiert:
Dies war die Leseprobe dieses Artikels.
Melden Sie sich an, um auf den vollständigen Artikel zuzugreifen.