EDM: Kunden verwalten mit Ribbon

EDM: Kunden verwalten mit Ribbon

Bisher haben wir in diesem Magazin nur einzelne Beispiele zur Darstellung von Daten aus Tabellen geliefert. Diesmal wollen wir einen Schritt weitergehen: Wir erstellen eine WPF-Anwendung, die ein eigenes Ribbon enthält und mit diesem die Steuerung einiger Funktionen zur Auflistung von Kunden sowie zum Bearbeiten, Hinzufügen und Löschen von Kundendatensätzen ermöglicht. Dabei nutzen wir als Container für die angezeigten Seiten mit der Kundenliste und den Kundendetails ein Frame-Objekt. Damit können wir, wenn mehrere Benutzer geöffnet sind, sogar durch die entsprechenden Seiten navigieren.

Dabei wollen wir zunächst eine Kundenübersicht und später eine Seite zum Anlegen eines neuen Kunden über entsprechende Ribbon-Steuerelemente sichtbar machen. Eine weitere Schaltfläche soll den aktuell in der Kundenübersicht markierten Kunden löschen.

Das heißt, dass wir zunächst ein Ribbon im Fenster MainWindow unserer Beispielanwendung benötigen, das drei Schaltflächen für die gewünschte Navigation in den Kundendatensätzen und eine Schaltfläche zum Schließen des Fensters enthält. Dies sollte später so wie in Bild 1 aussehen.

Erster Entwurf des Ribbons

Bild 1: Erster Entwurf des Ribbons

Um dies zu realisieren, legen Sie zunächst ein neues Projekt des Typs Visual C#|WPF-Anwendung namens NavigationMitRibbons an. Um die Ribbons zu definieren, benötigen Sie einen neuen Verweis, den Sie über den Verweis-Manager (Menü-Eintrag Projekt|Verweise) hinzufügen. Der Verweis heißt System.Windows.Controls.Ribbons.

Da wir dem Window-Element im Kopf ein Ribbon und darunter die Steuerelemente zur Anzeige der Artikel- und der Kundenübersicht hinzufügen wollen, legen wir zunächst ein Grid mit zwei Zeilen an. Diese definieren wir wie folgt:

<Grid.RowDefinitions>
     <RowDefinition Height="Auto"></RowDefinition>
     <RowDefinition></RowDefinition>
</Grid.RowDefinitions>

Anschließend fügen wir dem Grid ein Ribbon-Element mit zwei Schaltflächen in verschiedenen Gruppen hinzu, das wir über das Attribut Grid.Row="0" der ersten Ribbonzeile zuweisen (siehe Listing 1). Diesem fügen wir ein RibbonTab-Element mit zwei RibbonGroup-Elementen hinzu. Die erste Gruppe statten wir mit drei RibbonButton-Elementen aus und die zweite mit einem RibbonButton-Element. Die Schaltflächen versehen wir mit Attributen, die auf die jeweiligen Ereignismethoden verweisen. Außerdem legen wir mit der Eigenschaft LargeImageSource den Namen jeweils einer Bilddatei fest, die im Ribbon für die jeweilige Schaltfläche angezeigt werden soll. Diese Bilder legen wir in einem Unterordner namens images im Projektmappen-Explorer ab.

<Ribbon Name="rbnMain" Title="Beispielribbon" Grid.Row="0">
     <RibbonTab Name="Tab1" Header="Stammdaten" KeyTip="A">
         <RibbonGroup Header="Kunden">
             <RibbonButton Name="btnKundenuebersicht" Label="Kundenübersicht" Click="btnKundenuebersicht_Click" 
                 LargeImageSource="imagesusers.png"></RibbonButton>
             <RibbonButton Name="btnNeuerKunde" Label="Neuer Kunde" Click="btnNeuerKunde_Click" 
                 LargeImageSource="imagesuser_add.png"></RibbonButton>
             <RibbonButton Name="btnKundeLoeschen" Label="Kunde löschen" Click="btnKundeLoeschen_Click" 
                 LargeImageSource="imagesuser_delete.png" IsEnabled="false"></RibbonButton>
         </RibbonGroup>
         <RibbonGroup Header="Allgemein">
             <RibbonButton Name="btnSchliessen" Label="Schließen" Click="btnSchliessen_Click" 
                 LargeImageSource="imagesclose.png"></RibbonButton>
         </RibbonGroup>
     </RibbonTab>
</Ribbon>

Listing 1: Code für ein Ribbon mit Schaltflächen in verschiedenen Gruppen

Seiten erstellen

Nun wollen wir die beiden Seiten erstellen, die durch einen Mausklick auf die beiden Ribbon-Einträge angezeigt werden sollen. Dazu legen Sie zunächst ein erstes neues Page-Element an und nennen es Kundenuebersicht (Strg + Umschalt + A, dann Seite (WPF) auswählen und den Namen unten angeben) – siehe Bild 2.

Hinzufügen eines Page-Elements

Bild 2: Hinzufügen eines Page-Elements

Das Ergebnis ist ein transparentes, rechteckiges Objekt, für das weder Höhe noch Breite mit den üblichen Attributen Height oder Width festgelegt sind. Stattdessen finden wir die beiden Attribute d:DesignHeight und d:DesignWidth. Aber was sind das für Eigenschaften? Eigenschaften, die mit d: beginnen, sind Eigenschaften für die Design-Ansicht, die nur die Größe des Page-Elements für die Entwurfsansicht markieren.

Zur Laufzeit wird das Page-Element ja ohnehin in das Frame-Element eingebettet und nimmt dessen Größe an. Dementsprechend finden Sie im Page-Element die beiden Eigenschaften d:DesignHeight und d:DesignWidth. Das Attribut mc:Ignorable="d" gibt dem Interpreter zu verstehen, dass Attribute mit führendem d nicht interpretiert werden sollen:

<Page x:Class="NavigationMitRibbons.Kundenuebersicht" 
     ...
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300"
     Title="Kundenuebersicht">

Datenquelle

Als Datenquelle für dieses Beispiel verwenden wir wieder die Datenbank Bestellverwaltung, die Sie bereits in weiteren Artikeln in diesem Magazin kennen gelernt haben. Dazu haben wir wieder ein Entity Data Model namens BestellverwaltungEntities angelegt.

Page mit Kunden füllen

Damit das Page-Element die Kunden in einer entsprechenden Liste, hier in Form eines DataGrid-Elements, anzeigt, stellen wir zunächst eine entsprechende Datenquelle in Form eines List-Objekts in der Code behind-Datei Kundenuebersicht.xaml.cs zur Verfügung, die wir innerhalb der Konstruktor-Methode der Klasse füllen (siehe Listing 2).

public partial class Kundenuebersicht : Page {
     BestellverwaltungEntities dbContext;
     private List<Kunde> kunden;
     public List<Kunde> Kunden {
         get {
             return kunden;
         }
         set {
             kunden = value;
         }
     }
     public Kundenuebersicht(int kundeID = 0) {
         InitializeComponent();
         dbContext = new BestellverwaltungEntities();
         kunden = new List<Kunde>(dbContext.Kunden);
         DataContext = this;
         if (kundeID != 0) {
             Kunde currentKunde = dbContext.Kunden.Find(kundeID);
             dgKunden.SelectedItem = currentKunde;
             dgKunden.ScrollIntoView(currentKunde);
         }
     }
}

Listing 2: Code behind-Datei der Page-Klasse Kundenuebersicht.xaml

In der Konstruktor-Methode der Klasse Kundenuebersicht wird zunächst die Methode InitializeComponent ausgeführt, um das Fenster entsprechend der XAML-Definition aufzubauen. Danach erstellen wir das Entity Data Model-Objekt dbContext auf Basis der Klasse BestellverwaltungEntities. Die Liste kunden, die wir zuvor als privates List-Objekt deklariert haben, füllen wir dann mit der Auflistung Kunden des dbContext-Objekts:

kunden = new List<Kunde>(dbContext.Kunden);

Danach weisen wir dem Page-Objekt mit der DataContext-Eigenschaft als Datenherkunft die Code behind-Klasse selbst zu. Damit die Seite nun auf die Kunden-Liste aus der Variablen kunde zugreifen kann, stellen wir diese noch mit einer öffentlichen Variablen namens Kunden zur Verfügung:

public List<Kunde> Kunden {
     ...
}

Desweiteren haben Sie sicher bemerkt, dass wir einen optionalen Parameter namens kundeID für die Konstruktormethode angelegt haben. Diese wird in der if-Bedingung interessant: Ist kundeID nämlich nicht 0, was geschieht, wann immer eine Kunden-ID übermittelt wird, dann liest die Methode den Kunden mit dieser ID in die Variable currentKunde ein. Dieser wird dann im DataGrid als aktueller Kunde markiert. Die Methode ScrollIntoView sorgt dann noch dafür, dass diese Datensatz auch noch in den sichtbaren Bereich verschoben wird. Letzteres ist für Access/VBA-Programmierer natürlich ein Traum – dort waren für eine solche Aktion durchaus größere Verrenkungen nötig.

DataGrid-Element in Page anlegen

Schließlich wollen wir ein DataGrid-Element im Page-Element anlegen, das wie in Listing 3 definiert wird. Die Seite hat ja als Datenherkunft bereits die Code behind-Klasse erhalten. Damit brauchen wir für das DataGrid-Element namens dgKunden nur noch das Attribut ItemsSource auf den Wert {Binding Kunden} einzustellen.

<Page x:Class="Bestellverwaltung.Kundenuebersicht" ...  xmlns:local="clr-namespace:Bestellverwaltung"
       mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Title="Kundenuebersicht">
     <Grid>
         <DataGrid x:Name="dgKunden" ItemsSource="{Binding Kunden}" AutoGenerateColumns="false">
             <DataGrid.Columns>
                 <DataGridTextColumn Binding="{Binding Path=ID}" Header="ID" />
                 <DataGridTextColumn Binding="{Binding Path=Firma}" Header="Firma" />
                 <DataGridTextColumn Binding="{Binding Path=Vorname}" Header="Vorname" />
                 <DataGridTextColumn Binding="{Binding Path=Nachname}" Header="Nachname" />
             </DataGrid.Columns>
         </DataGrid>
     </Grid>
</Page>

Listing 3: Code für die Definition des Page-Elements zur Anzeige der Kundenübersicht

Es verwendet dann die Auflistung Kunden aus der Klasse Kundenuebersicht.xaml.cs als Datenquelle. Die Spalten sollen nicht automatisch erstellt werden, daher erhält AutoGenerateColumns den Wert false. Die Spalten legen wir unterhalb des Elements DataGrid.Columns an, und zwar als DataGridTextColumn-Elemente. Hier erhalten diese per Binding eine Verknüpfung zum jeweiligen Feld der Datenherkunft sowie per Header eine Spaltenüberschrift. Das Ergebnis soll anschließend wie in Bild 4 aussehen.

Das Page-Element mit den Kundendaten im Frame-Element des Window-Objekts

Bild 3: Das Page-Element mit den Kundendaten im Frame-Element des Window-Objekts

Wäre das Page-Objekt nun ein Window-Objekt, könnten wir es einfach öffnen und es würde die enthaltenen Daten anzeigen. Allerdings ist es kein Window-Objekt und soll als Page-Objekt in einem Frame-Element angezeigt werden.

Frame-Element zum Window hinzufügen

Deshalb fügen wir nun zunächst noch ein Frame-Element zum Window MainWindow.xaml hinzu. MainWindow.xaml sieht in gekürzter Form nun wie in Listing 4 aus. Beachten Sie, dass wir das Frame-Element mit dem Namen WorkZone versehen haben. Dies ist nötig, damit wir später auf dieses Element zugreifen und ihm den anzuzeigenden Inhalt zuweisen können.

<Window x:Class="NavigationMitRibbons.MainWindow" ... xmlns:local="clr-namespace:NavigationMitRibbons"
         mc:Ignorable="d" Title="MainWindow" Height="350" Width="525">
     <Grid>
         <Grid.RowDefinitions>...</Grid.RowDefinitions>
         <Ribbon Name="rbnMain" Title="Beispielribbon" Grid.Row="0">...</Ribbon>
         <Frame x:Name="WorkZone" Grid.Row="1"></Frame>
     </Grid>
</Window>

Listing 4: Gekürzte Fassung der Definition von MainWindow.xaml, jetzt mit dem Frame-Objekt

Frame-Element mit Page füllen

Fehlt noch der letzte Schritt: Ein Klick auf den Ribbon-Eintrag Kundenübersicht soll das Page-Element im Frame-Element einblenden und mit den Kundendaten füllen (siehe Bild 3).

Das DataGrid im Page-Element in der Entwurfsansicht

Bild 4: Das DataGrid im Page-Element in der Entwurfsansicht

Die Code behind-Klasse des Fensters MainWindow.xaml sehen Sie in Listing 5. Hier sind neben der Konstruktor-Methode noch zwei weitere Methoden zu sehen, die durch die beiden Schaltflächen des Ribbons ausgelöst werden. Die zweite davon heißt btnKundenuebersicht_Click. Wir haben diese bereits mit der einzigen Anweisung gefüllt, die eine weitere Methode namens ShowKundenuebersicht aufruft – auch diese ist im Quellcode abgebildet (den Parameter kundeID benötigen wir hier noch nicht, daher wird der Standardwert 0 verwendet).

public partial class MainWindow : Window {
     public MainWindow() {
         InitializeComponent();
     }
     public bool KundeChanged { get; set; }
     Kundenuebersicht kundenuebersicht;
     private void btnKundenuebersicht_Click(object sender, RoutedEventArgs e) {
         ShowKundenuebersicht();
     }
     private void ShowKundenuebersicht(int kundeID = 0) {
         if (kundenuebersicht == null | KundeChanged == true) {
             kundenuebersicht = new Kundenuebersicht(kundeID);
             KundeChanged = false;
         }
         WorkZone.Content = kundenuebersicht;
     }
}

Listing 5: Code behind-Datei der Klasse MainWindow.xaml

Die Methode prüft, ob die Objektvariable kundenuebersicht bereits gefüllt ist. Damit sorgen wir dafür, dass die Kundenübersicht nur neu erstellt wird, wenn sie noch nicht vorhanden ist. Ein anderer Grund, die Kundenübersicht neu zu erstellen, ist eine Änderung in den zugrunde liegenden Daten. Wenn also beispielsweise nach dem erstmaligen Füllen der Kundenübersicht einer der Kundendatensätze geändert oder ein neuer Kundendatensatz hinzugefügt wurde, soll die Kundenübersicht auch neu geladen werden. Dies prüfen wir über die Variable KundeChanged. Was es mit dieser Variable auf sich hat, lesen Sie im Artikel Kundendetails und im Artikel Events in der Praxis.

Sollte sowohl kundenuebersicht noch leer sein also KundeChanged den Wert true enthalten, soll die Kundenübersicht neu erstellt werden. Dies geschieht dann innerhalb der if-Bedingung. Die new-Anweisung erstellt ein neues Objekt des Typs Kundenuebersicht. Den Parameter kundeID erläutern wir später. Die Variable KundeChanged stellen wir nun wieder auf false ein, da ja die letzte Änderung durch Neuerstellen der Kundenübersicht berücksichtigt wurde.

Nach dem Abarbeiten der if-Bedingung weisen wir der Eigenschaft Content des mit WorkZone benannten Frame-Elements einfach die mit kundenuebersicht referenzierte Page zu.

Einblenden einer zusätzlichen Detailansicht für einen neuen Kunden

Nun wollen wir noch ein weiteres Page-Objekt namens Kundendetails ins Spiel bringen. Dieses soll angezeigt werden, wenn der Benutzer entweder doppelt auf einen der Einträge der Kundenliste geklickt hat oder wenn er die Ribbon-Schaltfläche zum Hinzufügen eines neuen Kunden betätigt hat. Erstellen wir zunächst die neue Page-Klasse. Diese soll nach dem Hinzufügen der Steuerelemente wie in Bild 5 aussehen (eine detaillierte Beschreibung dieser Klasse finden Sie im Artikel Kundendetails).

Das Page-Element mit den Detaildaten eines Kundendatensatzes in der Entwurfsansicht

Bild 5: Das Page-Element mit den Detaildaten eines Kundendatensatzes in der Entwurfsansicht

Bild 6 zeigt das gewünschte Aussehen eines Objekts der Klasse Kundendetails im Frame-Objekt unseres Hauptfensters der Anwendung. Die Deklaration für dieses Page-Objekt in der Code behind-Klasse sieht so aus:

Anzeige eines Kunden im Frame-Element per Page

Bild 6: Anzeige eines Kunden im Frame-Element per Page

Kundendetails kundendetails;

Fehlt noch der Code, mit dem wir einen neuen Kunden in dieser Ansicht einblenden. Diesen haben wir in Listing 6 abgebildet.Die Methode btnNeuerKunde_Click, die durch einen Mausklick auf die Ribbon-Schaltfläche Neuer Kunde ausgelöst wird, erstellt ein neues Objekt des Typs Kundendetails, also des gleichnamigen Page-Objekts, und speichert es in der Variablen kundendetails. Es abonniert die beiden Ereignisse ItemAdded und Cancelled dieses Objekts (weitere Infos siehe Artikel Kundendetails) und weist das neue Page-Objekt mit dem neuen Kunden dem Frame-Objekt als Content zu.

public partial class MainWindow : Window {
     ...
     private void btnNeuerKunde_Click(object sender, RoutedEventArgs e) {
         kundendetails = new Kundendetails(dbContext);
         kundendetails.ItemAdded += new Kundendetails.EventHandlerItemAdded(OnItemAdded);
         kundendetails.Cancelled += new Kundendetails.EventHandlerCancelled(OnCancelled);
         WorkZone.Content = kundendetails;
     }
     private void OnItemAdded(object sender, KundeEventArgs e) {
         Kunde kunde = e.KundeBearbeitet;
         KundeChanged = true;
         ShowKundenuebersicht(kunde.ID);
     }
     private void OnCancelled(object sender, EventArgs e) {
         ShowKundenuebersicht();
     }
}

Listing 6: Methode zum Anlegen eines neuen Kunden

Die Methode OnItemAdded wird ausgelöst, wenn der Benutzer auf die Speichern-Schaltfläche der Page namens Kundendetails klickt. Sie liest den neu hinzugefügten Kunden ein, der über den zweiten Parameter geliefert wird, stellt KundeChanged auf den Wert True ein (damit die Kundenübersicht beim erneuten Anzeigen aktualisiert wird) und ruft die bereits weiter oben vorgestellte Methode ShowKundenuebersicht auf.

Im Gegensatz zu dem Aufruf durch die Schaltfläche btnKundenuebersicht wird hier der Primärschlüsselwert des Kundendatensatzes als Parameter übergeben, damit der neu hinzugefügte Kunde gleich markiert werden kann – mehr dazu haben Sie bereits weiter oben erfahren.

Bei Abbrechen

Sollte der Benutzer auf der Seite Kundendetails nach dem Bearbeiten die Abbrechen-Schaltfläche betätigt haben, löst dies die Implementierung OnCancelled aus, die wiederum einfach nur die Methode ShowKundenuebersicht aufruft. Da hier nun kundeChanged nicht auf true eingestellt wurde, wird diese Methode einfach nur die gegebenenfalls bereits erstellte Instanz der Seite Kundenuebersicht im Frame-Element anzeigen.

Ausgewählten Kunden aufrufen

Wenn der Benutzer einen der Kunden im DataGrid markiert und doppelt auf diesen klickt, soll der Kunde auf der Seite Kundendetails angezeigt werden. Für eine Zeile des DataGrid-Elements gibt es kein eingebautes Ereignis, sodass wir dieses erst noch definieren müssen. Dazu fügen Sie dem Code des DataGrid-Elements in der Klasse Kundenuebersicht.xaml die folgenden Zeilen hinzu:

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

Die entsprechende Methode fügen Sie der Klasse Kundenuebersicht.xaml.cs hinzu. Sie sieht wie in Listing 7 aus. Die Methode schreibt den mit dem Parameter sender übergebenen Verweis auf die Zeile in die Variable row.

public partial class Kundenuebersicht : Page {
     ...
     private void Row_DoubleClick(object sender, 
             System.Windows.Input.MouseButtonEventArgs e) {
         DataGridRow row = sender as DataGridRow;
         Kunde kunde = row.DataContext as Kunde;
         if (kunde == null) {
             return;
         }
         MainWindow wnd = (MainWindow)Window.GetWindow(this);
         wnd.KundendetailsAnzeigen(kunde.ID);
     }
}

Listing 7: Methode zum Anzeigen des aktuell im DataGrid markierten Kunden

Die DataContext-Eigenschaft dieses Elements liefert ein Objekt des Typs Kunde, welches wir mit der Variablen kunde referenzieren. Ist kunde nicht null, löst dies die Methode KundendetailsAnzeigen mit dem Primärschlüsselwert des Kunden aus, was die Seite Kundendetails mit dem ausgewählten Kunden einblenden soll.

Details anzeigen

Die hier erwähnte Methode KundendetailsAnzeigen finden Sie in Listing 8. Sie erwartet über den Parameter kundeID den Primärschlüsselwert des anzuzeigenden Kunden. Dieser wird gleich an die Konstruktormethode Kundendetails der Klasse weitergeleitet, wo – wie im Artikel Kundendetail beschrieben – der entsprechende Kunde angezeigt wird.

public partial class MainWindow : Window {
     ...
    public void KundendetailsAnzeigen(int kundeID) {
         kundendetails = new Kundendetails(dbContext, kundeID);
         kundendetails.ItemChanged += new Kundendetails.EventHandlerItemChanged(OnItemChanged);
         kundendetails.Cancelled += new Kundendetails.EventHandlerCancelled(OnCancelled);
         WorkZone.Content = kundendetails;
     }
     private void OnItemChanged(object sender, KundeEventArgs e) {
         Kunde kunde = e.KundeBearbeitet;
         KundeChanged = true;
         ShowKundenuebersicht(kunde.ID);
     }
}

Listing 8: Methode zum Bearbeiten eines vorhandenen Kunden

Die Methode KundendetailsAnzeigen abonniert außerdem die beiden Ereignisse ItemChanged und Cancelled und zeigt dann die neue Kundendetails-Seite im Frame-Element des Fensters an.

Die Methode OnItemChanged, die auf das Ereignis ItemChanged reagiert, erhält mit dem Parameter e des Typs KundeEventArgs einen Verweis auf den bearbeiteten Kunden. Dieser soll dann gleich in der Kundenübersicht als zuletzt bearbeiteter Kunde markiert werden, wofür die Methode ShowKundenuebersicht mit der Kunden-ID als Parameter sorgt.

Kunden löschen

Fehlt noch eine Funktion, mit der sich der aktuell im DataGrid markierte Kunde löschen lässt. Diese soll ebenfalls per Ribbon-Schaltfläche verfügbar gemacht werden. Vor dem Löschen soll noch eine Meldung erscheinen, die den Benutzer fragt, ob der Kunde wirklich gelöscht werden soll (siehe Bild 7).

Rückfrage vor dem Löschen eines Kunden

Bild 7: Rückfrage vor dem Löschen eines Kunden

Die Methode, die durch die Schaltfläche btnKundeLoeschen ausgelöst wird, finden Sie in Listing 9. Die Methode speichert zunächst das mit SelectedItem ermittelte Kunde-Objekt in der Variablen kunde. Dann zeigt es eine MessageBox an, die den Benutzer fragt, ob der Kunde mit der entsprechenden ID gelöscht werden soll.

private void btnKundeLoeschen_Click(object sender, RoutedEventArgs e) {
     Kunde kunde = (Kunde)kundenuebersicht.dgKunden.SelectedItem;
     MessageBoxResult result = MessageBox.Show("Den Kunden mit der ID '" + kunde.ID + "' wirklich löschen?",
         "Kunde löschen", MessageBoxButton.YesNo);
     if (result == MessageBoxResult.Yes) {
         BestellverwaltungEntities context = new BestellverwaltungEntities();
         Kunde kundeDelete = context.Kunden.Find(kunde.ID);
         context.Kunden.Remove(kundeDelete);
         context.SaveChanges();
         kundenuebersicht = new Kundenuebersicht();
         WorkZone.Content = kundenuebersicht;
     }
}

Listing 9: Methode zum Löschen des aktuell markierten Kunden

Ist dies der Fall, erstellt die Methode einen neuen Datenbankkontext und ermittelt darauf den Kunden, der gelöscht werden soll. Dieser landet wiederum in der Variablen kundeDelete. Die Remove-Methode der Kunden-Liste der Datenbank löscht dann den entsprechenden Kunden aus dem Entity Data Model und speichert die Änderung dann direkt mit der SaveChanges-Methode in der zugrunde liegenden Tabelle. Danach wird die Kundenübersicht neu erstellt und im Frame-Element eingeblendet.

Löschen-Schaltfläche aktivieren und deaktivieren

Die Löschen-Schaltfläche des Ribbons soll natürlich nicht immer aktiviert sein, sondern nur, wenn die Kundenübersicht im Frame-Element angezeigt wird. Damit diese Schaltfläche standardmäßig erst einmal deaktiviert ist, weil ja beim Starten der Anwendung zunächst noch gar keine Seite im Frame-Element sichtbar ist, stellen wir die Eigenschaft IsVisible im .xaml-Code entsprechend ein:

<RibbonButton Name="btnKundeLoeschen" Label="Kunde löschen" Click="btnKundeLoeschen_Click" LargeImageSource="imagesuser_delete.png" IsEnabled="false"></RibbonButton>

Um die Schaltfläche in Abhängigkeit vom jeweils angezeigten Page-Element zu aktivieren oder zu deaktivieren, wollen wir uns zunächst mit einer einfachen Lösung behelfen. Dazu legen Sie für das Attribut Navigated des Elements WorkZone den Wert WorkZone_Navigated an und erstellen die entsprechende Ereignismethode:

<Frame x:Name="WorkZone" Grid.Row="1" Navigated="WorkZone_Navigated"></Frame>

Diese prüft in einer switch-Bedingung den in einen String konvertierten Wert der Content-Eigenschaft, welche den Namespace und den Namen des jeweils angezeigten Objekts liefert. Lautet der Name Bestellverwaltung.Kundenuebersicht, soll die Schaltfläche btnKundeLoeschen im Ribbon aktiviert werden, anderenfalls wird diese deaktiviert (siehe Listing 10). Im Artikel PropertyChanged in der Praxis schauen wir uns allerdings noch eine elegantere Lösung an. Dabei wollen wir dafür sorgen, dass statt der Eigenschaft des Steuerelements btnKundeLoeschen selbst nur eine lokale Variable geändert wird, die aber an das entsprechende Attribut im XAML-Code des Objekts btnKundeLoeschen gebunden ist.

private void WorkZone_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e) {
     switch (WorkZone.Content.ToString()) {
         case "Bestellverwaltung.Kundenuebersicht":
             btnKundeLoeschen.IsEnabled = true;
             break;
         default:
             btnKundeLoeschen.IsEnabled = false;
             break;
     }
}

Listing 10: Aktivieren und deaktivieren der Ribbon-Schaltfläche

Hauptfenster schließen

Fehlt noch eine Methode, um das Hauptfenster zu schließen. Die entsprechende Schaltfläche heißt btnSchliessen und wurde bereits zu Beginn des Artikels im XAML-Code untergebracht. Die durch diese Schaltfläche ausgelöste Methode sieht wie folgt aus und ruft die Close-Methode des mit this referenzierten Fensters auf:

private void btnSchliessen_Click(object sender, 
         RoutedEventArgs e) {
     this.Close();
}

Zusammenfassung und Ausblick

Gemeinsam mit den weiterführenden Artikeln Events in der Praxis und Kundendetails erhalten Sie eine erste kleine Lösung, mit der Sie die Kundendaten einer Datenbanktabelle verwalten können, und dies komplett in einem Fenster.

Dieses wechselt bei Bedarf die Ansicht von der Kundenübersicht zu den Kundendetails und ermöglicht auch das Neuanlegen von Kundendaten.

Der Artikel ProperyChanged in der Praxis erweitert die Lösung noch um eine etwas schönere Lösung für das Aktualisieren der Ribbon-Schaltfläche zum Löschen eines Kunden-Datensatzes. Die beiden Artikel EDM: Ausnahmen beim Speichern behandeln und EDM: Validieren von Entitäten mit IValidatableObject zeigen noch, wie Sie eine grundlegende Validierung zur Lösung hinzufügen können.

In den kommenden Ausgaben werden wir die Lösung noch erweitern und beispielsweise zeigen, wie Sie zusätzlich noch Artikel verwalten. Dazu verwenden wir grundsätzlich ähnliche Elemente, bauen aber noch ein paar WPF-spezifische Elemente mehr ein. In diesem ersten Schritt wollten wir Ein- und Umsteiger von Access/VBA noch nicht mit allzu vielen neuen Techniken überfrachten.

Bitte geben Sie die Zahlenfolge in das nachfolgende Textfeld ein

Die mit einem * markierten Felder sind Pflichtfelder.

Aktuell im Blog
Onlinebanking mit Access

Es ist geschafft: Endlich ist das Buch Onlinebanking mit Access fertiggeschrieben. Das war... [mehr]

Direktzugriff auf Tabellen und Felder

Die IntelliSense-Erweiterung für Tabellen und Felder hat mir soviel Spaß gemacht, dass ich gleich... [mehr]

IntelliSense für Tabellen und Felder

Wenn Sie mit dem VBA-Editor arbeiten und dort gelegentlich SQL-Anweisungen eingeben, müssen Sie... [mehr]

Download Access und SQL Server

Erfahren Sie, welche Schritte zum Download des aktuellen Stands des Buchs "Access und SQL Server"... [mehr]

Bilder in Access 2013

Wer die Bibliothek mdlOGL0710 von Sascha Trowitzsch oder ein ähnliches Modul aus meinen... [mehr]

Dynamische Ribbons

Immer wieder fragen Leser, wie man Ribbon-Elemente wie etwa Schaltflächen in Abhängigkeit... [mehr]

Die Blogmaschine

Einen kleinen Blog zusätzlich zum Shop zu betreiben ist eine tolle Sache. Hier lassen sich... [mehr]

Wegwerfadressen für die Newsletteranmeldung

Die Verwendung von Wegwerf-Adressen für die Nutzung aller möglichen Online-Dienste nimmt... [mehr]

Access und Facebook

Facebook und Access - das ist eine der wenigen Kombinationen, die ich noch nicht in die Mangel... [mehr]

Access und SQL Server - das Projekt

Mein neues Buch Access und SQL Server (gemeinsam mit Bernd Jungbluth) geht in die Endphase. Wer... [mehr]