Nachdem wir die Funktionen zum Abrufen von Kontoständen und Umsätzen sowie für das Überweisen programmiert haben, können wir uns an den Entwurf einer Benutzeroberfläche für diese Funktionen begeben. Diese soll kompakte Formulare für die wichtigsten bereits behandelten Onlinebanking-Funktionen enthalten. Dazu gehört die Auswahl von Bankaccount und Konto sowie die Anzeige von Umsätzen und Kontostand. Dies erledigen wir im Hauptfenster der Anwendung. Ein weiteres Fenster erlaubt dann das Ausführen einer Überweisung für das aktuell im Hauptfenster ausgewählte Konto. Außerdem benötigen wir noch eine Tabelle, mit der wir die abgefragten Umsatzdaten speichern können. Diese fügen wir per Entity Framework hinzu.
Voraussetzungen
Voraussetzung für das Umsetzen der Lösung dieses Artikels ist das Vorhandensein einer DDBAC-Lizenz. Die damit nutzbaren Komponenten sind leider nicht mehr kostenlos verfügbar, sondern müssen lizensiert werden, bevor man diese in seine Produkte einbauen kann. Lizenzen finden Sie im Onlineshop unter https://shop.minhorst.com/access-tools/295/ddbac-jahreslizenzc=78.
Vorbereitungen
Als Projekt legen wir ein neues Projekt des Typs Visual Basic|Windows Desktop|WPF-App an.
Dann fügen wir ein neues Element des Typs ADO.NET Entity Data Model hinzu. Dieses dient dazu, ein Entity Data Model zu erstellen und über dieses automatisch eine Datenbank mit der benötigten Tabelle zu generieren. Nachdem Sie mit dem Menü-befehl Projekt|Neues Element hinzufügen… den Dialog Neues Element hinzufügen geöffnet haben, tragen Sie den Namen des Entity Data Models ein (hier OnlinebankingContext) und klicken auf Hinzufügen. Im nun erscheinenden Assistent für Entity Data Model wählen Sie den Typ Leeres Code First-Modell aus. Wenige Sekunden später hat der Assistent die notwendigen Elemente hinzugefügt.
Durch diesen Schritt haben wir außerdem direkt Änderungen an der Datei App.config vorgenommen. Dort steht nun im Element connectionStrings die Verbindungszeichenfolge, mit der wir später die Datenbank zum Speichern der Umsätze erstellen und verwenden.
Außerdem benötigen wir noch eine Referenz auf die DDBAC-Komponenten, die den Zugriff auf Ihre Konten überhaupt erst ermöglichen. Dazu fügen Sie dem Projekt den Verweis aus Bild 1 hinzu.
Bild 1: Verweis auf die DDBAC-Bibliothek
Kontostand anzeigen
Wir beginnen mit der Anzeige des Kontostands. Hier wollen wir in einem Fenster die Auswahl des Kontakts und anschließend des gewünschten Kontos erlauben. Per Klick auf eine Schaltfläche soll dann der Kontostand eingelesen und in einem Textfeld angezeigt werden. Wie Sie bereits in den vorherigen Artikeln erfahren haben, legen wir die Kontakte und Konten über die Systemsteuerung an, und zwar über die App Homebanking Administrator (32-Bit). Auf die dort angelegten und synchronisierten Elemente können wir dann per Code zugreifen.
Ein neues WPF-Fenster soll nun zunächst ein Kombinationsfeld zur Auswahl des Kontakts anbieten. Nachdem der Benutzer dort einen Eintrag ausgewählt hat, sollen die zum gewählten Kontakt gehörenden Konten in einem zweiten Kombinationsfeld angezeigt werden. Das passende Steuer-element für diesen Zweck ist jeweils das ComboBox-Element. Also fügen wir zunächst zwei solche Elemente im Hauptfenster MainWindow.xaml an. Damit die zusätzlich angelegten Bezeichnungsfelder optisch ansprechend dargestellt werden, erstellen wir zuvor einige Spalten und Zeilen im bereits vorhandenen Grid-Element.
Klasse für die Kontakte anlegen
Die über die Systemsteuerung hinzufügten Onlinebanking-Kontakte lesen wir mithilfe der im Artikel Onlinebanking mit DDBAC: Saldo und Umsätze beschriebenen Funktion ein, die wir jedoch leicht abwandeln. Die eingelesenen Daten sollen je Kontakt in einer neuen Instanz der nachfolgend beschriebenen Klasse landen:
Public Class Contact Public BankCode As String Public CountryCode As String Public UserID As String End Class
Diese Klasse legen Sie als neues Element im Projekt an und speichern es unter Contact.vb. Wir benötigen allerdings die INotifyPropertyChanged-Schnittstelle in dieser Klasse, daher ändern wir diese wie folgt.
Wir fügen außerdem noch eine Eigenschaft namens BACContact hinzu, mit der wir einen Verweis auf das BACContact-Objekt speichern, aus dem wir die Eigenschaften der Klasse ausgelesen haben:
Imports System.ComponentModel Public Class Contact Implements INotifyPropertyChanged Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged Protected Overridable Sub OnPropertyChanged(propname As String) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propname)) End Sub Private _bankCode As String Private _countryCode As String Private _userID As String Private _bACContact As BACContact Public Property BankCode As String Get Return _bankCode End Get Set(value As String) _bankCode = value OnPropertyChanged("BankCode") End Set End Property Public Property CountryCode As String Get Return _countryCode End Get Set(value As String) _countryCode = value OnPropertyChanged(CountryCode) End Set End Property Public Property UserID As String Get Return _userID End Get Set(value As String) _userID = value OnPropertyChanged("UserID") End Set End Property Public Property BACContact As BACContact Get Return _bACContact End Get Set(value As BACContact) _bACContact = value End Set End Property End Class
Klasse für die Konten anlegen
Die Klasse für die Konten sieht ähnlich aus wie die für die Kontakte. Auch hier implementieren wir die INotifyPropertyChanges-Schnittstelle. Die Klasse bietet die Eigenschaften AccountNumber, AcctName, BIC und IBAN an. Darüberhinaus wollen wir das BACAccount-Objekt, über das wir die Klasse füllen, mit den Instanzen der Klasse speichern. Die Klassendefinition sieht wie folgt aus:
Imports System.ComponentModel Imports BankingApplicationComponents Public Class Account Implements INotifyPropertyChanged Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged Protected Overridable Sub OnPropertyChanged(propname As String) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propname)) End Sub Private _accountNumber As String Private _acctName As String Private _bIC As String Private _iBAN As String Private _bACAccount As BACAccount Public Property AccountNumber As String Get Return _accountNumber End Get Set(value As String) _accountNumber = value OnPropertyChanged("AccountNumber") End Set End Property ... weitere Property-Eigenschaften Public Property BACAccount As BACAccount Get Return _bACAccount End Get Set(value As BACAccount) _bACAccount = value End Set End Property End Class
Auflistung mit Kontakt-Elementen füllen
Wenn die Anwendung gestartet und somit das Fenster MainWindow.xaml geöffnet wird, sollen die Kontakte aus der Systemsteuerung eingelesen und in jeweils eine neue Klasse des Typs Contact geschrieben werden. Die neuen Instanzen wollen wir außerdem direkt zu einer Liste hinzufügen, die wir anschließend dem ersten ComboBox-Element zuweisen können. Wir nutzen dazu eine Funktion namens GetBACContacts, die eine Liste von Elementen des Typs BACContact liefert. Diese fügen wir einem Modul namens DDBACObjects.vb hinzu, dem wir außerdem noch per Imports-Anweisung die Elemente des Namespace BankingApplicationComponents hinzufügen.
Die folgende privat deklarierte Variable speichert die Contacts-Auflistung zwischen, damit diese nicht bei jedem Zugriff erneut ausgelesen werden müssen:
Private m_Contacts As BACContacts
Die Funktion GetBACContacts liest die Kontakte mit den Methoden der DDBAC-Bibliothek aus der Systemsteuerung in die Variable m_BACContacts ein. Diese wird dann anschließend auch als Ergebnis der Funktion zurückgegeben. Wenn m_BACContacts bereits vorhanden ist, wird die Auflistung nicht erneut gefüllt. Einzige Ausnahme ist, wenn der Aufruf den Wert True für den Parameter bolReset enthält. In diesem Fall werden die Kontakte auf jeden Fall erneut eingelesen:
Public Function GetBACContacts(Optional bolReset As Boolean = False) As BACContacts If m_BACContacts Is Nothing Then m_BACContacts = New BACContacts m_BACContacts.Populate("") Else If bolReset = True Then m_BACContacts.Populate("") End If End If Return m_BACContacts End Function
Damit haben wir mit GetBACContacts eine Liste der BACContact-Elemente eingelesen. Diese müssen wir nun noch in eine ObservableCollection mit Elementen des oben definierten Typs Contact umfüllen. Diese Liste wollen wir dann als Datenquelle des ersten ComboBox-Elements in unserem Fenster verwenden. Diese Aufgabe übernimmt die Funktion GetContacts. Sie erstellt eine neue ObservableCollection in der Variablen objContacts. Dann durchläuft sie eine For Each-Schleife über alle BACContact-Elemente, welche die oben beschriebene Funktion GetContacts liefert. Innerhalb der Schleife legt sie ein neues Contact-Element an (nicht zu verwechseln mit BACContact), und schreibt die entsprechenden Werte in die Eigenschaften BankCode, CountryCode und UserID sowie einen Verweis auf das aktuelle BACContact-Objekt in die Eigenschaft BACContact. Anschließend fügt sie das neu erstellte und gefüllte Objekt zur ObservableCollection hinzu:
Public Function GetContacts() As ObservableCollection(Of Contact) Dim objContacts As ObservableCollection(Of Contact) Dim objContact As Contact Dim objBACContact As BACContact objContacts = New ObservableCollection(Of Contact) For Each objBACContact In GetBACContacts() objContact = New Contact With objContact .BankCode = objBACContact.BankCode .CountryCode = objBACContact.CountryCode .UserID = objBACContact.UserID .BACContact = objBACContact objContacts.Add(objContact) End With Next Return objContacts End Function
Auflistung für die Konten füllen
Wenn der Benutzer in der gleich noch zu erstellenden ComboBox einen Kontakt ausgewählt hat, soll die zweite ComboBox die zu diesem Kontakt gehörenden Konten zur Auswahl anbieten. Deshalb benötigen wir analog zu den oben beschriebenen Funktionen GetBACContacts und GetContacts eine weitere Funktion.
Die Funktion GetBACAccounts erwartet als Parameter ein BACContact-Objekt, zu dem sie die BACAccount-Objekte einlesen soll. Sie verwendet dann schlicht die Accounts-Auflistung des BACContact-Objekts, um die Liste in der Variablen m_Accounts des Typs BACAccounts zu speichern:
Public Function GetBACAccounts(objBACContact As BACContact) As BACAccounts Return objBACContact.Accounts End Function
Wenn der Benutzer im ersten ComboBox-Feld mit den Kontakten einen Eintrag ausgewählt hat, holen wir mit der folgenden Funktion die Daten zum Füllen des zweiten ComboBox-Feldes zur Anzeige der Konten dieses Kontakts. Dabei verwenden wir auch hier als Parameter das BACContact-Element des zu untersuchenden Kontaktes. Die Funktion erstellt als Erstes wieder eine neue ObservableCollection.
In einer For Each-Schleife durchlaufen wir diesmal die mit der Funktion GetBACAccounts geholten Konten. Innerhalb der For Each-Schleife legen wir ein neues Objekt des Typs Account an und weisen diesem die Werte für die Eigenschaften AccountNumber, AcctName, IBAN und BIC zu sowie einen Verweis auf das BACAccount-Objekt dieses Kontos. Anschließend fügen wir es der ObservableCollection namens objAccounts zu, die wir als Funktionsergebnis zurückliefern:
Public Function GetAccounts(objBACContact As BACContact) As ObservableCollection(Of Account) Dim objAccounts As ObservableCollection(Of Account) Dim objAccount As Account Dim objBACAccount As BACAccount objAccounts = New ObservableCollection(Of Account) For Each objBACAccount In GetBACAccounts(objBACContact) objAccount = New Account With objAccount .AccountNumber = objBACAccount.AccountNumber .AcctName = objBACAccount.AcctName .BIC = objBACAccount.BIC .IBAN = objBACAccount.IBAN .BACAccount = objBACAccount End With objAccounts.Add(objAccount) Next Return objAccounts End Function
Fenster zur Anzeige der Auswahlfelder für Kontakte und Konten
Das Fenster soll im oberen Bereich zwei ComboBox-Elemente zur Auswahl von Kontakten und Konten anzeigen. Im Kontakt-Kombinationsfeld wollen wir die UserID und die Bankleitzahl anzeigen. Das Konto-Auswahlfeld soll nur die IBAN anzeigen. Die Definition dieser beiden Steuer-elemente sieht wie folgt aus. Als Erstes das ComboBox-Element cboContacts, das an die Auflistung Contacts gebunden ist, die wir gleich noch im Code behind-Modul definieren.
Das ComboBox-Element hat außerdem ein Attribut für das Ereignis SelectionChanged. Da wir zwei Felder im ComboBox-Element anzeigen wollen, stellen wir diese in einem ItemTemplate und den entsprechenden untergeordneten Elementen wie folgt dar:
<Label Grid.Column="0" Content="Kontakt:"/> <ComboBox x:Name="cboContacts" Grid.Row="0" Grid.Column="1" Width="200" ItemsSource="{Binding Contacts}" SelectedValuePath="UserID" SelectionChanged="CboContacts_SelectionChanged"> <ComboBox.ItemTemplate> <DataTemplate> <TextBlock> <TextBlock.Text> <MultiBinding StringFormat="{}{0} {1}"> <Binding Path="UserID" /> <Binding Path="BankCode" /> </MultiBinding> </TextBlock.Text> </TextBlock> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox>
Das zweite ComboBox-Element für die Konten ist an die Liste Accounts gebunden. Sie soll nur das Feld IBAN anzeigen und löst ebenfalls das Ereignis SelectionChanged aus:
<Label Grid.Column="0" Grid.Row="1" Content="Konto:"/> <ComboBox x:Name="cboAccounts" Grid.Row="1" Grid.Column="1" Width="200" ItemsSource="{Binding Accounts}" SelectedValuePath="IBAN" SelectionChanged="CboAccounts_SelectionChanged" DisplayMemberPath="IBAN"> </ComboBox>
Code behind-Klasse des Fensters
Die Code behind-Klasse verwendet die folgenden beiden Namespaces:
Imports System.Collections.ObjectModel Imports System.ComponentModel
Außerdem implementiert sie die INotifyPropertyChanged-Schnittstelle:
Class MainWindow Implements INotifyPropertyChanged Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged Protected Overridable Sub OnPropertyChanged(propname As String) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propname)) End Sub
Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Visual Basic Entwickler:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 200 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein: