EDM: Bilder speichern und anzeigen

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.

EDM: Bilder speichern und anzeigen

In der Bestellverwaltung haben wir bisher nur mit einfachen Daten in Datentypen wie Text, Zahl oder Datum gearbeitet. Dabei kann man doch mit WPF auch wunderbar Bilddateien anzeigen. In diesem Artikel erweitern wir die Datenbank Bestellverwaltung um das Speichern und die Anzeige von Bildern zu den Produktdatensätzen.

Speicherort: Tabellenfeld oder Dateisystem?

Eine der wichtigsten Fragen, wenn es darum geht, Bilder mit einer Datenbank zu verwalten, ist die nach dem Speicherort der Bilder. Grundsätzlich gibt es zwei einfache Varianten: Die Bilder werden im Dateisystem gespeichert und die Datenbank hält nur die Dateipfade zu den Bildern in den jeweiligen Datensätzen vor. Oder Sie speichern die Bilder direkt in einem entsprechenden Feld in der Datenbank. Wir werden an dieser Stelle, an der wir mit einer SQLite-Datenbank arbeiten, die Variante mit dem Dateisystem wählen, und zwar aus folgenden Gründen:

  • Datenbanken sind dazu gemacht, referenziell verknüpfte Daten zu speichern, diese zu indizieren und schnell zugreifbar zu machen oder zu ändern. Das Speichern von Bildern oder anderen Dateien in den Tabellen der Datenbank ist da eher kontraproduktiv.
  • Wenn Sie die Bilder in der Datenbankdatei speichern und die Daten sichern wollen, müssen Sie immer die komplette Datenbank inklusive der enthaltenen Bilder sichern. Wenn sich die Bilder im Dateisystem etwa in einem Ordner im gleichen Verzeichnis wie die Datenbank befinden, können diese separat gesichert werden, was nur dann nötig ist, wenn sich diese geändert haben.
  • Zum Bearbeiten oder Anzeigen müssen die Bilder in der Regel entweder ohnehin im Dateisystem gespeichert oder aber anderweitig in den Speicher geladen werden. Dann kann man sie auch direkt aus dem Dateisytem heraus öffnen.

Optimalerweise speichern wir die Bilder auch noch in einem Verzeichnis, dass sich auf der gleichen Ebene oder unterhalb der Anwendung befindet. Auf diese Weise brauchen wir nur den relativen Pfad zur Bilddatei in der Datenbank zu speichern.

Tabelle Produkte erweitern

Damit wir die Bilder, die wir im Dateisystem speichern, mit den Datensätzen der Tabelle Produkte verknüpfen können, fügen wir dieser Tabelle ein Feld namens Bild hinzu. Es soll ein einfaches Textfeld sein, dass den Pfad zur Bilddatei speichert, und zwar relativ zur Datenbank in einem eigenen Ordner namens Bilder.

Diese Änderung nehmen wir der Einfachheit halber über das Tool SQLiteStudio vor. Dort öffnen Sie die Datenbank Bestellverwaltung und klicken dann doppelt auf die Tabelle Produkte. Nun betätigen Sie die Schaltfläche Add column (Ins) wie in Bild 1.

Anlegen eines neuen Feldes

Bild 1: Anlegen eines neuen Feldes

Dies öffnet den Dialog aus Bild 2. Hier tragen Sie den Namen des neuen Feldes sowie den Datentyp ein. Anschließend schließen Sie den Dialog mit der OK-Schaltfläche.

Anlegen des Feldes Bild

Bild 2: Anlegen des Feldes Bild

Erst der Klick auf die Schaltfläche Commit structure changes öffnet den Dialog Auszuführende Abfragen, der die SQL-Abfragen mit den geplanten Änderungen anzeigt und per Klick auf OK die Änderung in die Datenbank überträgt (siehe Bild 3).

SQL-Anweisung zum Anlegen der Tabelle mit dem Feld Bild

Bild 3: SQL-Anweisung zum Anlegen der Tabelle mit dem Feld Bild

Nun müssen wir die Änderung in der Datenbank noch in das Entity Data Model übertragen. Dazu öffnen Sie die Ansicht Bestellverwaltung.edmx und wählen aus dem Kontextmenü den Eintrag Modell aus der Datenbank aktualisieren... aus (siehe Bild 4).

Aktualisieren des Entity Data Models

Bild 4: Aktualisieren des Entity Data Models

Danach erscheint das Feld Bild dann auch im Element Produkt des Entity Data Models. Nun können wir also Bildpfade zum Feld Bild des Elements Produkt hinzufügen. Damit sind die Arbeiten am Entity Framework erledigt.

XAML-Code definieren

Nun wollen wir das Aussehen des Fensters zur Anzeige der Produktdaten mit den Bildern definieren. Dies erledigen wir diesmal gleich im Fenster MainWindow.XAML. Damit die Steuer­elemente wie gewünschten angeordnet werden, haben wir über die Elemente Grid.RowDefinitions und Grid.ColumnDefinitions einige Zeilen und Spalten definiert. Die Definition dieser Elemente sieht wie folgt aus, wobei die Position des Elements mit dem Wert * für das Attribut Height eine besondere Rolle spielt:

<Grid.RowDefinitions>
     <RowDefinition Height="Auto"></RowDefinition> //für Header
     <RowDefinition Height="Auto"></RowDefinition> //für ListBox
     <RowDefinition Height="Auto"></RowDefinition> //für ID des Produkts
     <RowDefinition Height="Auto"></RowDefinition> //für Bezeichnung
     <RowDefinition Height="Auto"></RowDefinition> //für Bildpfad
     <RowDefinition Height="*"></RowDefinition> //für Image-Steuerelement
     <RowDefinition Height="Auto"></RowDefinition> //für Schaltflächen
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
     <ColumnDefinition Width="Auto"></ColumnDefinition>
     <ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>

Hier hinterlegen wir nun das ListBox-Steuerelement, das in der zweiten Zeile über zwei Spalten angeordnet werden soll. Dieses fügen wir in der folgenden Form zum XAML-Code hinzu:

<ListBox x:Name="lstProdukte" Grid.Row="1" Grid.ColumnSpan="2" Margin="5" ItemsSource="{Binding Produkte}" DisplayMemberPath="Bezeichnung" SelectionChanged="lstProdukte_SelectionChanged"/>

Das ListBox-Element heißt lstProdukte und ist an die Auflistung Produkte als ItemsSource gebunden. Angezeigt soll der Inhalt der Eigenschaft Bezeichnung des gebundenen Objekts. Wenn sich die Auswahl ändert, etwa weil der Benutzer ein anderes Element anklickt, soll dies die Ereignisprozedur lstProdukte_SelectionChanged auslösen. Damit das ListBox-Element die Elemente der Produkte auflistet, fügen wir der Code behind-Klasse MainWindow.xaml.cs einige Codezeilen hinzu. Den Beginn macht die klassenweite Definition des DBContext-Elements:

BestellverwaltungEntities dbContext;

Damit wir die Produkte als Datenherkunft für die ListBox haben und das einzelne Produkt-Objekt als Datenherkunft für die Steuer­elemente des Fensters, definieren wir außerdem noch eine private Variable für die Liste der Produkte, und zwar für eine ObservableCollection mit Elementen des Typs Produkt:

private ObservableCollection<Produkt> produkte;

Den Inhalt dieser Variablen wollen wir auch öffentlich zugänglich machen, damit wir die Elemente des XAML-Codes daran binden können. Dies erledigen wir wie folgt:

public ObservableCollection<Produkt> Produkte {
     get { return produkte; }
     set { produkte = value; }
}

Auch für das jeweils mit den Textfeldern anzuzeigende Produkt, dessen Bild wir ja auch laden wollen, deklarieren wir ein Objekt namens produkt, dass eine Instanz des Typs Produkt speichern kann:

private Produkt produkt;

Die öffentliche Eigenschaft kann über den Namen Produkt gelesen und geschrieben werden. Damit beim Füllen der Variablen produkt gleich die daran gebundenen Steuerelemente aktualisiert werden, implemtieren wir die Schnittstelle INotifyPropertyChanged für die aktuelle Klasse. Der Teil in der öffentlichen Eigenschaft Produkt erhält dazu im Setter einen Aufruf der Methode OnPropertyChanged:

public Produkt Produkt {
     get { return produkt; }
     set {
         produkt = value;
         OnPropertyChanged(new PropertyChangedEventArgs("Produkt"));
     }

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.