EDM: 1:n-Beziehungen mit DataGrid

Lies in den Artikel rein und unten bekommst Du ein unschlagbares Angebot!

Unter Access haben wir 1:n-Beziehungen einfach in einem Haupt- und einem Unterformular abgebildet, wobei wir beiden einfach die Datenquellen und gebundenen Steuerelemente zugewiesen haben – den Rest hat Access automatisch erledigt. Unter C# und WPF ist das ein wenig mehr Arbeit, aber nach der Lektüre dieses Artikels haben Sie das Wissen, das für die Anzeige zweier per 1:n-Beziehung verknüpfter Tabellen in einem Fenster beziehungsweise einer Seite und einem DataGrid als Unterformular-Ersatz nötig ist.

Beispieldaten

Als Beispiel wollen wir uns die Kategorien und die damit verknüpften Produkte ansehen. Dabei sollen die beiden Felder einer Kategorie im Fenster/in der Seite selbst angezeigt werden, die dazugehörigen Produkte in einem DataGrid unter den Kategoriedaten. Wir verwenden die SQLite-Datenbank Bestellverwaltung.db und ein daraus abgeleitetes Entity Data Model namens BestellverwaltungEntities.edmx als Datenquelle. Die verwendeten Auflistungen beziehungsweise Entitäten heißen Kategorien, Kategorie, Produkte und Produkt.

Einbau in die Bestellverwaltung

In einigen weiteren Beiträgen verwenden wir die Bestellverwaltung als Beispielanwendung. Diese verwendet im Office-Stil ein Ribbon zur Auswahl der verschiedenen Bereiche und Funktionen. Die einzelnen Bereiche etwa zur Anzeige einer Kundenliste oder einer Kundendetailansicht werden auf Seiten (Page) statt auf eigenen Fenstern (Window) erstellt und je nach angeklickter Ribbon-Schaltfläche in einem Frame-Element eingeblendet – also etwa wie die Unterformulare in einem Unterformular-Steuerelement in Access. Wir fügen also in diesem Artikel weitere Page-Elemente hinzu, die dann nach dem Anklicken der ebenfalls noch anzulegenden Ribbon-Schaltflächen angezeigt werden sollen.

Ribbon-Einträge

Als Erstes legen wir die drei Ribbon-Einträge an, die Sie in Bild 1 sehen. Die Elemente für diese Ribbon-Gruppe sehen wie folgt aus:

Übersicht der Kategorien

Bild 1: Übersicht der Kategorien

<RibbonGroup Header="Kategorien">    //MainWindow.xaml
     <RibbonButton Name="btnKategorieuebersicht" Label="Übersicht" Click="btnKategorieuebersicht_Click"
         LargeImageSource="images/elements4.png"></RibbonButton>
     <RibbonButton Name="btnNeueKategorie" Label="Neue Kategorie" Click="btnNeueKategorie_Click" 
         LargeImageSource="images/elements4_new.png"></RibbonButton>
     <RibbonButton Name="btnKategorieLoeschen" Label="Kategorie löschen" Click="btnKategorieLoeschen_Click" 
         LargeImageSource="images/elements4_delete.png"></RibbonButton>
</RibbonGroup>

Wir haben für jedes Element ein Bild hinterlegt, das wir gleichzeitig zum Ordner images des Projekts hinzugefügt haben.

Übersichtsseite für die Kategorien

Die Kategorien werden in der Übersichtsseite KategorieUebersicht.xaml in einem DataGrid-Element aufgelistet. Das Füllen dieses DataGrid-Elements erfolgt genauso, wie wir es bereits im Artikel EDM: Kunden verwalten mit Ribbon für die Anzeige der Kunden realisiert und im Artikel Bestellveraltung planen angepasst haben – nur, dass wir diesmal auf die Entitätsliste der Kategorien statt der Kunden zugreifen und nur die Felder ID und Bezeichnung anzeigen.

Detailseite für die Kategorien

Der interessante Teil folgt nun, nämlich die Detailseite für eine Kategorie. Eine Kategorie enthält zwar nur die beiden Felder ID und Bezeichnung, was sich genau so leicht abbilden lässt wie in der Detailansicht für Kunden (Kundendetails.xaml) – nur mit weniger Feldern. Allerdings wollen wir ja zu jeder Kategorie auch noch die Liste der Produkte anzeigen, die der jeweiligen Kategorie zugeordnet sind! Und das wollen wir wiederum mit einem DataGrid-Element erledigen.

Im Grunde brauchen wir also eine Kombination der bereits einmal gezeigten Detailansicht für die Kunden (diesmal für die Kategorien) und einer Übersicht für die Produkte. Der Unterschied bei der Übersichtsseite diesmal ist, dass wir nicht mehr einfach alle Elemente der Produkte-Liste anzeigen können, sondern nur noch diejenigen Elemente, die der aktuellen Kategorie zugeordnet sind. Die Definition der Seite mit den Kategoriedetails und der Produktliste startet mit ein paar Page.Resources-Elementen, welche globale Attribute der verschiedenen Steuerelemente festlegen und die wir hier ebenso gekürzt haben wie die Definition des Grids:

<Page x:Class="Bestellverwaltung.Kategoriedetails" ...Title="Kategoriedetails">    //Kategoriedetails.xaml
     <Page.Resources>...</Page.Resources>
     <Grid>
         <Grid.ColumnDefinitions>...</Grid.ColumnDefinitions>
         <Grid.RowDefinitions>...</Grid.RowDefinitions>

Danach folgt das Label für die ID der Kategorie und die TextBox, die wir an das Feld kategorie.ID binden:

         <Label Content="ID:" Grid.Column="0" />
         <TextBox x:Name="txtID" Grid.Column="1" HorizontalAlignment="Left" Text="{Binding kategorie.ID, Mode=TwoWay,             ValidatesOnExceptions=true}" Width="50" IsEnabled="False" BorderBrush="Transparent" />

Die Bezeichnung erhält ebenfalls ein Label und eine Bindung an das Feld kategorie.Bezeichnung – beide landen in jeweils einer Spalte, genau wie die Steuerelemente für die ID:

         <Label Content="Bezeichnung:" Grid.Column="0" Grid.Row="1" />
         <TextBox x:Name="txtBezeichnung" Grid.Column="1" HorizontalAlignment="Stretch" Grid.Row="1"             Text="{Binding kategorie.Bezeichnung, Mode=TwoWay, ValidatesOnDataErrors=true}" />

Schließlich folgt das DataGrid-Element namens dgProdukte, das in der folgenden Zeile landet und sich über zwei Spalten erstrecken soll (Grid.ColumnSpan=”2″). Als ItemsSource für das DataGrid legen wir das Element Produkte fest. Das automatische Generieren der Spalten sowie das Anzeigen einer leeren Spalte zum Hinzufügen von Elementen deaktivieren wir:

         <DataGrid x:Name="dgProdukte" Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" ItemsSource="{Binding Produkte}"                 AutoGenerateColumns="false" CanUserAddRows="False">

Die beiden Spalten des DataGrid-Elements binden wir an die Felder ID und Bezeichnung:

             <DataGrid.Columns>
                 <DataGridTextColumn Binding="{Binding Path=ID}" Header="ID"  />
                 <DataGridTextColumn Binding="{Binding Path=Bezeichnung}" Header="Produkt" />
             </DataGrid.Columns>

Außerdem wollen wir, wie schon bei den übrigen Übersichten, ein Öffnen der Produktdetails per Doppelklick erlauben und fügen dazu einen EventSetter hinzu:

             <DataGrid.Resources>
                 <Style TargetType="DataGridRow">
                     <EventSetter Event="MouseDoubleClick" Handler="Row_DoubleClick"/>
                 </Style>
             </DataGrid.Resources>
         </DataGrid>

Schließlich folgen noch die beiden Schaltflächen zum Speichern und Verwerfen der aktuellen Änderungen:

         <StackPanel Orientation="Horizontal" Grid.Row="6" Grid.ColumnSpan="4" >
             <Button x:Name="btnSpeichern" Margin="3" Padding="3" Click="btnSpeichern_Click" Height="23"                 Content="Speichern"></Button>
             <Button x:Name="btnVerwerfen" Margin="3" Padding="3" Click="btnVerwerfen_Click" Height="23"                 Content="Verwerfen"></Button>
         </StackPanel>
     </Grid>
</Page>

Der Entwurf sieht in der XAML-Ansicht nun wie in Bild 2 aus. Im Entwurf haben wir nun schon einige Bindungen gesehen, die wir nun in der Code behind-Klasse bereitstellen wollen. Diese Klasse enthält zunächst eine Variable für das DBContext-Element, über das wir auf das Entity Data Model zugreifen (dbContext). Außerden finden wir hier die Definition für die Objekte, an die wir die Elemente der XAML-Seite binden wollen. Die erste ist das Kategorie-Objekt, das wir in der öffentlichen Variablen kategorie speichern.

 

Schreibe einen Kommentar