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.
Validieren mit VB und EDM
Im Artikel EDM: Validieren von Entitäten mit IDataErrorInfo haben wir bereits erläutert, wie Sie einer auf dem Entity Framework basierenden Anwendung eine Validierung hinzufügen können. Im vorliegenden Artikel schauen wir uns an, wie Sie die Validierung nicht unter C#, sondern unter VB realisieren und welche Änderungen in den Methoden zum Migrieren einer Access-Anwendung nach WPF/EDM notwendig sind, um die Validierung vorzubereiten oder gegebenenfalls auch direkt umzusetzen.
Für die Programmierung einer Validierung in den Klassen des Entity Data Models und der mit WPF definierten Benutzeroberfläche sind einige Schritte auf den verschiedenen Ebenen erforderlich. Der erste ist, die Entitätsklassen mit der Implementierung der Schnittstelle IDataErrorInfo zu versehen, die zweite die Definition der Anzeige der Validierungsmeldungen in der Benutzeroberfläche – und das geschieht durch entsprechende WPF-Elemente.
IDataErrorInfo – wo implementieren?
Im oben genannten Artikel haben wir unter C# die Schnittstelle IDataErrorInfo für partielle Klassen implementiert. Das bedeutet, dass wir zwei gleichnamige Klassen programmiert haben, wobei wir in der einen die Definition der Properties und in der anderen die Implementierung der Schnittstelle IDataErrorInfo eingefügt haben. Warum haben wir das dort so gemacht? Weil wir den Code für die Entitätsklassen aus dem Datenmodell der Datenbank generiert haben, was bedeutet, dass wir bei Änderungen des Datenmodells auch die Entitätsklassen neu generieren mussten. Wenn wir dann die Implementierung der Schnittstelle IDataErrorInfo in der automatisch generierten Entitätsklasse programmiert hätte, wäre diese bei jeder Aktualisierung wieder überschrieben worden. Deshalb haben wir diese Definition direkt in eigenen, partiellen Klassen programmiert. Partielle Klasse bedeutet dabei, dass wir einfach eine weitere Klasse gleichen Namens mit dem Schlüsselwort Partial erstellt und dort die Elemente für die Implementierung der Schnittstelle hineingeschrieben haben. Die Klassenbezeichnungen der per Generator erzeugten Entitätsklassen wurden dabei praktischerweise bereits mit dem Schlüsselwort Partial ausgezeichnet – was keinen Nachteil bringt, auch wenn es keine weiteren partiellen Klassen mehr gibt.
Nun verwenden wir in der aktuell in diesem Magazin beschriebenen Vorgehensweise eine Access-Datenbank als Vorlage für die Erstellung eines Entity Data Models und auch für die Erstellung von Fenstern auf Basis der Formulare der Access-Datenbank. Wir könnten also theoretisch auch gleich die Implementierung der Schnittstelle IDataErrorInfo in die Entitätsklassen schreiben – und hier direkt die im Datenmodell festgelegten Restriktionen wie keine Nullwerte et cetera eintragen. Allerdings kann es auch hier sein, dass Sie die Implementierung der Schnittstelle IDataErrorInfo selbst anpassen wollen. Also werden wir auch hier mit partiellen Klassen arbeiten und per Parameter beim Erstellen des Entity Data Models auf Basis der Tabellen der Access-Datenbank die Möglichkeit bieten, entweder nur das Entity Data Model zu erstellen oder auch noch die partiellen Klassen mit den Validierungsfunktionen neu zu generieren. Zunächst schauen wir uns allerdings an, wie die partiellen Klassen unter VB überhaupt aussehen sollen.
Partielle Klasse mit IDataErrorInfo erstellen
Das Anlegen der zusätzlichen partiellen Klasse etwa für die Klasse Kunde erfordert zwei Schritte. Als Erstes fügen wir der eigentlichen Klasse das Schlüsselwort Partial als erstes Schlüsselwort noch vor Public hinzu:
<Table("Kunden")>
Partial Public Class Kunde
...
End Class
Danach können wir die zweite partielle Klasse erstellen:
Partial Public Class Kunde
...
End Class
Für diese Klasse wollen wir nun die Schnittstelle IDataErrorInfo implementieren. Dazu benötigen wir zunächst die Bibliothek System.ComponentModel, die wir per Imports-Anweisung hinzufügen:
Imports System.ComponentModel
Danach fügen Sie in der Zeile unter der Klassendefinition die Anweisung zur Implementierung der Schnittstelle hinzu:
Partial Public Class Kunde
Implements IDataErrorInfo
...
Wenn Sie mit der rechten Maustaste auf IDataErrInfo klicken, erscheint der Kontextmenü-Eintrag Schnellaktionen und Refactorings..., den Sie anklicken und danach den nun erscheinenden Befehl Schnittstelle implementieren anklicken (siehe Bild 1).
Bild 1: Automatisches Implementieren der SchnittstelleDas füllt die Klasse mit den beiden Properties Item und [Error]:
Partial Public Class Kunde
Implements IDataErrorInfo
Default Public ReadOnly Property Item(columnName As String) As String Implements IDataErrorInfo.Item
Get
Throw New NotImplementedException()
End Get
End Property
Public ReadOnly Property [Error] As String Implements IDataErrorInfo.Error
Get
Throw New NotImplementedException()
End Get
End Property
End Class
Uns interessiert dabei speziell die Property namens Item. Diese liefert mit dem Parameter columnName den Namen des Feldes, für das eine Validierung durchgeführt werden soll. Um eine Validierung für das Feld Vorname durchzuführen, die prüfen soll, ob das Feld Vorname leer ist, fügen Sie die folgende Select Case-Bedingung mit dem Case-Zweig für den Feldnamen Vorname hinzu. Die Prüfung stellt mit der Methode IsNullOrEmpty fest, ob Vorname leer ist. In diesem Fall wird der Rückgabeparameter strErrorMessage mit einer entsprechenden Fehlermeldung gefüllt:
Default Public ReadOnly Property Item(columnName As String) As String Implements IDataErrorInfo.Item
Get
Dim strErrorMessage As String = ""
Select Case columnName
Case "Vorname"
If (String.IsNullOrEmpty(Vorname)) Then
strErrorMessage = "Bitte geben Sie einen Vornamen ein."
End If
End Select
Return strErrorMessage
End Get
End Property
Nun stellt sich nur noch die Frage, wodurch diese Methode aufgerufen wird und wie wir die Fehlermeldung aus strErrorMessage verarbeiten.
Auslösen der Validierung
Dass für das Feld Vorname eine Validierung ausgelöst wird, legen wir in der Definition des an dieses Feld gebundenen Steuerelements fest, in diesem Fall des Textfeldes txtVorname. Hier erweitern wir den Inhalt der Bindung für das Attribut Text um ValidatesOnDataErrors=True:
<TextBox x:Name="txtVorname" Text="{Binding Kunde.Vorname, ValidatesOnDataErrors=True}" Height="21" Margin="118,58,0,0" Width="221"/>
Damit allein wird nun bereits die Validierung ausgelöst, das heißt, wenn das Feld Vorname angezeigt wird, ruft dies auch die Methode Item der Implementierung von IDataErrorInfo auf. Das Ergebnis ist allerdings noch keine Anzeige der Meldung, sondern zunächst nur das rote Einrahmen des Feldes, das nicht erfolgreich validiert werden konnte (siehe Bild 2).
Bild 2: Die Validierung funktioniert bereits.
Wir wollen allerdings noch konkretere Hinweise auf den Grund für die farbige Markierung liefern, damit der Benutzer weiß, was zu tun ist. Also verwenden wir den Setter, den wir auch schon im oben genannten Artikel genutzt haben, um die Fehlermeldung an entsprechender Stelle unterzubringen. Dazu erweitern wir den Code für das Style-Element in der .xaml-Datei wie folgt:
<Style TargetType="{x:Type TextBox}">
...
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel>
<Border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10" ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
<TextBlock Text="!" VerticalAlignment="center" HorizontalAlignment="center" FontWeight="Bold" Foreground="white" />
</Border>
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
<Border BorderBrush="red" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Danach erscheint die Meldung, die wir für das Feld Vorname definiert haben, wie in Bild 3.
Bild 3: Validierung mit Hinweismeldung
Validierung von Kombinationsfeldern
Für die Validierung des Kombinationsfeldes Anrede fügen Sie in der .xaml-Datei für die Definition des Style-Elements für den Typ ComboBox genau die gleiche Property namens Validation.ErrorTemplate wie für den Typ TextBox hinzu:
<Style TargetType="{x:Type ComboBox}">
...
<Setter Property="Validation.ErrorTemplate">
...
</Setter>
</Style>
Außerdem passen Sie in der Definition des ComboBox-Elements das Attribut SelectedItem so an, dass die Bindung mit der Option ValidatesOnDataErrors=True erfolgt:
<ComboBox x:Name="cboAnredeID" Padding="0" Height="21" Margin="118,111,0,0" Width="78"
ItemsSource = "{Binding Anreden}"
SelectedItem = "{Binding Kunde.Anrede, ValidatesOnDataErrors=True}"
...
</ComboBox>
Schließlich erweitern wir die Implementierung der Schnittstelle IDataErrorInfo noch um einen entsprechenden Case-Zweig. Hier verwenden wir allerdings die IsNothing-Funktion, um zu prüfen, ob für die Eigenschaft Anrede eines der Elemente der Auflistung Anreden zugewiesen wurde:
Default Public ReadOnly Property Item(columnName As String) As String Implements IDataErrorInfo.Item
Get
Dim strErrorMessage As String = ""
Select Case columnName
...
Case "Anrede"
If (IsNothing(Anrede)) Then
strErrorMessage = "Bitte wählen Sie eine Anrede aus."
End If
End Select
Return strErrorMessage
End Get
End Property
Verlassen des Datensatzes ohne erfolgreiche Validierung unterbinden
Nun müssen wir noch sicherstellen, dass der Benutzer den Datensatz nicht verlassen kann, ohne dass alle erforderlichen Daten eingegeben wurden. Dazu haben wir im oben genannten Artikel eine Technik kennengelernt, die auf den Ergebnissen unserer Validierung aufbaut und davon abhängig Steuerelemente aktiviert oder deaktiviert. Dabei haben wir für die betroffene Schaltfläche DataTrigger-Element als Style-Elemente festgelegt und für jeden Trigger eine Bedingung formuliert, unter der eine bestimmte Eigenschaft auf einen Wert eingestellt werden soll – in diesem Fall etwa der Wert der Validierung eines oder mehrerer gebundener Steuerelemente und damit verbunden die Eigenschaft IsEnabled der zu deaktivierenden Schaltfläche.
Daraus leiten wir für unsere Steuerelemente, hier etwa für die Schaltfläche btnErster, die entsprechende Style-Definition ab. Die Style.Triggers-Auflistung nimmt dabei mehrere DataTrigger-Elemente auf. Diese referenzieren jeweils die Eigenschaft Validation.HasError eines der Steuerelemente, in der nachfolgenden verkürzten Form etwa die Textfelder txtFirma oder txtEMail. Ist Validation.HasError den Wert True, wird der eingefasste Setter aktiviert, der hier den Wert der Eigenschaft IsEnabled auf True einstellt:
<Button x:Name="btnErster" Content="<<" Click="btnErster_Click" Width="25" Margin="2,2,2,2">
<Button.Style>
Dies war die Leseprobe dieses Artikels.
Melden Sie sich an, um auf den vollständigen Artikel zuzugreifen.