Bestellverwaltung á la Visual Basic

Bestellverwaltung á la Visual Basic

In einer Umfrage haben uns viele Leser bescheinigt, dass Sie viel besser mit Visual Basic-Code arbeiten würden anstatt den großen Schritt von VBA auf C# zu wagen. Also wollen wir uns in diesem Artikel einmal ansehen, wie es aussieht, wenn wir unsere in den bisherigen Ausgaben entwickelte Beispielanwendung auf VB umstellen. Eines vorweg: Wir müssen nicht den kompletten Code anfassen, denn die Benutzeroberfläche haben wir ja vollständig mit XAML beschrieben. Aber auch der Rest liefert noch eine Menge Arbeit, wie die folgenden Seiten zeigen werden ...

Die erste Frage, die sich stellt, ist die nach der richtigen Vorgehensweise. Das C#-Projekt, das wir umwandeln möchten, besteht aus Code behind-Klassen mit C#-Code, die zu den Window- und Page-Objekten gehören, Klassendateien auf Basis von C# (.cs) und Konfigurationsdateien, die mit Sicherheit an der einen oder anderen Stelle festlegen, in welcher Sprache das Projekt programmiert wurde. So ist die AssemblyInfo.cs-Datei beispielsweise auch in der jeweiligen Sprache programmiert. Beginnen wir bei der .sln-Datei, welche die Lösung zusammensetzt – in unserem Fall ja nur aus dem reinen Anwendungsprojekt. Die dort referenzierte Projektdatei hat die Dateiendung .csproj, womit die C#-Affinität auch schon ausgeschöpft ist:

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bestellverwaltung", "BestellverwaltungBestellverwaltung.csproj", "{FCD792BB-5FC8-4BC1-A66B-4165B450B126}"

In der .csproj-Datei finden sich beispielsweise die Referenzen, wozu auch eine auf die C#-Bibliothek gehört:

<Reference Include="Microsoft.CSharp" />

Danach folgen die Einträge für die einzelnen Klassen (.xaml.cs) und die dazugehörigen .xaml-Dateien sowie die übrigen .cs-Dateien, die zum Beispiel wie folgt aussehen:

<Compile Include="Kundenuebersicht.xaml.cs">
     <DependentUpon>Kundenuebersicht.xaml</DependentUpon>
</Compile>

Können wir nun also die entsprechenden Stellen in diesen Dateien ändern, die .cs-Dateien durch .vb-Dateien ersetzen und die Anwendung starten? So einfach ist es leider nicht. Wir finden beispielsweise keine Möglichkeit, etwa eine .vb-Klasse zum C#-Projekt hinzuzufügen. Selbst wenn wir eine neue VB-Klasse außerhalb des Projekts erstellen und es dann per Drag and Drop in den Projektmappen-Explorer zum Projekt hinzufügen, wird es zwar automatisch in der .csproj-Datei referenziert. Die darin enthaltene Klasse kann jedoch von den anderen C#-Klassen aus nicht referenziert werden.

Aus C# mach VB

Also legen wir ein neues VB-Projekt namens Bestellverwaltung_VB an. Dazu wählen Sie im Dialog Neues Projekt die Vorlage Visual Basic|Windows|WPF-Anwendung aus (siehe Bild 1).

Anlegen des VB-Projekts

Bild 1: Anlegen des VB-Projekts

Das VB-Projekt ist ähnlich aufgebaut wie ein C#-Projekt auf Basis der Vorlage WPF-Anwendung. Wir bekommen gleich die Klasse MainWindow zu Gesicht – allerdings hat die Code behind-Klasse diesmal mit der Dateiendung .xaml.vb.

Konverter

Hier setzen wir direkt an und wollen die Code behind-Klasse des Fensters MainWindow der C#-Anwendung, also MainWindow.xaml.cs, in die Datei MainWindow.xaml.vb übertragen. Dazu verwenden wir einen automatischen Code-Konverter wie den auf der Webseite converter.telerik.com. Hier wählen Sie die gewünschte Übersetzung aus, hier also etwa C# to VB, und kopieren den zu übersetzenden Code in das linke Fenster. Nach einem Klick auf die Schaltfläche Convert Code wird dieser in das rechte Fenster konvertiert (siehe Bild 2).

Automatisches Übersetzen des VB-Codes

Bild 2: Automatisches Übersetzen des VB-Codes

Wie dies gelungen ist, wird sich zeigen, wenn wir nach und nach alle Elemente übersetzt haben. Dazu kopieren wir zunächst den Inhalt des rechten Fensters in die Klasse MainWindow.xaml.vb. Das liefert einige Fehlermeldungen, die zum größten Teil daraus resultieren, dass die dort referenzierten Klassen nicht vorhanden sind (siehe Bild 3).

Beim Einfügen erscheinen einige Fehlermeldungen ...

Bild 3: Beim Einfügen erscheinen einige Fehlermeldungen ...

Die erste können wir bereits beheben, indem wir einen Verweis auf die Klasse System.Windows.Controls.Ribbon hinzufügen, und zwar über den Dialog Verweis-Manager, den wir über den Menüeintrag Projekt|Verweise öffnen (siehe Bild 4).

Verweis auf die Ribbon-Klasse hinzufügen

Bild 4: Verweis auf die Ribbon-Klasse hinzufügen

Code temporär auskommentieren

Anschließend kommentieren wir fast den kompletten Code erst einmal aus. Dazu markieren Sie die auszukommentierenden Teile und betätigen die Tastenkombination Strg + K, C. Wir lassen nur die folgenden Zeilen übrig, um von dort aus Stück für Stück die entsprechenden Teile wieder in die Klasse einzubinden:

Imports System.Windows.Controls.Ribbon
Namespace Bestellverwaltung
     Partial Public Class MainWindow
         Inherits RibbonWindow
#Region "Allgemein"
         Private vorherigeSeite As String
         Private aktuelleSeite As String
         Public Sub New()
             InitializeComponent()
             WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen
         End Sub
#End Region
     End Class
End Namespace

An dieser Stelle erhalten wir nur noch eine Fehlermeldung, und zwar für die Anweisung InitializeComponent(). Diese entfernen wir zunächst einfach.

XAML-Code kopieren

Der XAML-Code sollte keine Referenz auf die als Code behind-Datei verwendete .cs-Datei haben, sondern nur auf die Klasse beziehungsweise den Namespace. Also kopieren Sie einfach den kompletten Inhalt der Datei MainWindow.xaml des C#-Projekts in die gleichnamige Datei des neu erstellten VB-Projekts. Das Ergebnis sieht schon recht gut aus. Wir müssen allerdings noch die Bilddateien nachreichen, denn diese liegen ja noch nicht im Zielprojekt vor (siehe Bild 5). Um dies zu erledigen, würden wir nun am lieben einfach den Ordner images aus dem Projektmappen-Explorer des C#-Projekts in den des VB-Projekts ziehen. Das gelingt allerdings nicht.

Die Bilddateien fehlen noch.

Bild 5: Die Bilddateien fehlen noch.

Bilder hinzufügen

Also ziehen wir einfach den Ordner images aus dem Windows Explorer in den Projektmappen-Explorer des VB-Projekts. Das gelingt, allerdings erscheinen die enthaltenen Bilddateien dort nicht! Allerdings wurde das Verzeichnis images im Projektordner im Dateisystem mit den enthaltenen Dateien angelegt. Deshalb ziehen wir die Bilder noch aus dem images-Verzeichnisses im Projektordner des VB-Projekts in den Ordner images im Projektmappen-Explorer. Danach erscheinen dort nicht nur die Bilder, sondern auch im Ribbon (siehe Bild 6).

Anlegen der fehlenden Bilddateien

Bild 6: Anlegen der fehlenden Bilddateien

Versendungen-Fenster

Als Erstes nehmen wir nun das Fenster hinein, welches durch einen Klick auf die Ribbon-Schaltfläche btnVersendungen angezeigt wird. Dazu nehmen wir die Kommentarzeichen für die folgenden Zeilen in der Klasse MainWindow.xaml.vb wieder weg:

Private Sub btnVersendungen_Click(sender As Object, e As RoutedEventArgs)
     Dim wnd As New Versendungen()
     wnd.ShowDialog()
End Sub

Hier wird die Klasse Versendungen rot markiert, da diese ja noch gar nicht im Projekt enthalten ist. Also holen wird dies nach, indem wir eine neue Window-Klasse namens Versendungen anlegen. Dann kopieren wir den kompletten XAML-Code aus der Klasse Versendungen.xaml des C#-Projekts und fügen diesen in die neu erstellte Klasse im VB-Projekt ein. Sie brauchen hier nur den Namespace für das Attribut xmlns:local des Window-Elements auf Bestellverwaltung_VB zu ändern.

Dann kopieren wir auch hier einfach den Inhalt der Klasse Versendungen.xaml.cs in das linke Fenster der Webseite http://converter.telerik.com/ und erzeugen mit einem Klick auf Convert Code den entsprechenden VB-Code. Daraus resultieren wiederum einige rote Markierungen und entsprechende Einträge in der Fehlerliste von Visual Studio (siehe Bild 7). Die meisten davon beziehen sich auf fehlende Objekte wie Versendung, Kunde oder KundeVersendung. Spätestens, wenn wir das nicht definierte Objekt BestellverwaltungEntities entdecken, wird dann klar, dass wir ja noch gar nicht das Entity Data Model zur Datenbank hinzugefügt haben.

Fehler in der Datei Verwendungen.xaml.vb

Bild 7: Fehler in der Datei Verwendungen.xaml.vb

Entity Data Model hinzufügen

Die zum Erstellen des Entity Data Model notwendigen Schritte in aller Kürze:

  • System.Data.SQLite mit NuGet hinzufügen
  • Nummer der hinzugefügten Version merken und auf https://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki die passende Version der Designtime-Komponenten herunterladen (im vorliegenden Fall die Version 1.06, also die Datei sqlite-netFx46-setup-bundle-x86-2015-1.0.106.0.exe).
  • Die Designtime-Komponenten installieren, dazu muss Visual Studio geschlossen werden.
  • Die Datenbankdatei Bestellverwaltung.db aus dem Ordner des C#-Projekts in den VB-Ordner kopieren.
  • Visual Studio wieder öffnen und als neues Element des Typs ADO.NET Entity Data Model namens BestellverwaltungEntities zum Projekt hinzufügen.
  • Im Assistent für Entity Data Model eine neue Verbindung erstellen, welche sich auf die in den Projektordner kopierte Datenbankdatei bezieht und den Typ System.Data.SQLite Database File aufweist. Dort dann alle Tabellen der Datenbank auswählen.
  • Auf Fertigstellen klicken und einige Augenblicke warten. Danach liegt das Entity Data Model BestellverwaltungEntities.edmx im Projektmappen-Explorer vor.

Allerdings verschwinden die Fehlermeldungen zum größten Teil immer noch nicht. Das liegt daran, dass die Tabellen in der Datenbank Namen in der Pluralform tragen (zum Beispiel Kunden), die dann auch als Bezeichnungen der Entitäten übernommen wurden. Dies ändern Sie noch im Diagramm des Entitiy Data Models und speichern die Änderungen dann mit der Tastenkombination Strg + S. Anschließend sind auch die meisten Fehler aus der Klasse Versendungen.xaml.vb verschwunden. Interessant ist an dieser Stelle, dass der Eintrag BestellverwaltungEntities.edmx unter Visual Basic keine Untereinträge anzeigt wie im C#-Projekt (siehe Bild 8).

Das .edmx-Element zeigt unter VB keine Unterelemente an, unter C# schon.

Bild 8: Das .edmx-Element zeigt unter VB keine Unterelemente an, unter C# schon.

INotifyPropertyChanged richtig implementieren

Nun ist nur noch die folgende Zeile fehlerhaft, wobei der Name der Schnittstelle INotifyPropertyChanged farbig markiert wird:

Implements INotifyPropertyChanged

Die Implementierung ist jedoch vorhanden und sieht auch korrekt aus:

Public Event PropertyChanged As PropertyChangedEventHandler
Private Sub NotifyPropertyChanged(name As String)
     RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
End Sub

Was tun? Wir kommentieren einfach die Zeile, die Public Event beginnt, aus, und verwenden die Funktion Schnellaktionen und Refactorings..., die wir nach einem Rechtsklick auf den als fehlerhaft markierten Eintrag aus dem Kontextmenü auswählen können. Im anschließend erscheinenden Popup wählen wir dann den Eintrag Schnittstelle implementieren aus (siehe Bild 9), was die folgende Zeile anlegt:

Implementieren per Schnellaktionen und Refactorings...

Bild 9: Implementieren per Schnellaktionen und Refactorings...

Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

Erster Test des konvertierten Teils der Anwendung

Damit können wir nun einen ersten Test der Anwendung wagen. Dabei hagelt es allerdings Fehler, wie Bild 10 zeigt. Dies sind jedoch nur die fehlenden Ereignismethoden für die Schaltflächen des Ribbons. Nun haben Sie zwei Möglichkeiten: Sie entfernen die jeweiligen Attribute namens Click aus den betroffenen Definitionen der Schaltflächen im XAML-Code, oder Sie entfernen einfach die Kommentarzeichen (') der jeweils ersten und letzten Zeile der Prozeduren – wie etwa in folgendem Beispiel:

Es hagelt Fehler beim ersten Start der Anwendung.

Bild 10: Es hagelt Fehler beim ersten Start der Anwendung.

Private Sub btnNeuerKunde_Click(sender As Object, e As RoutedEventArgs)
     '    KundendetailsAnzeigen()
End Sub

Der nächste Start der Anwendung liefert dann bereits die erste lauffähige Version (siehe Bild 11). Damit kümmern wir uns nun um die übrigen Elemente der Anwendung und lassen uns überraschen, ob uns noch weitere Herausforderungen erwarten.

Der erste Teil der Anwendung läuft!

Bild 11: Der erste Teil der Anwendung läuft!

Schritt für Schritt

Dabei können wir nun Schritt für Schritt die soeben bereits teilweise vom Kommentarzeichen befreiten Ereignismethoden der Klasse MainWindow.xaml.cs komplett von Kommentarzeichen befreien. Die dabei auftauchenden Fehlermeldungen behandeln wir dann direkt.

Wenn wir dabei oben im Code der Ausgangsdatenbank beginnen, gelangen wir zunächst zu den beiden Zeilen, welche die Objekte auf Basis der Page-Klassen Kundenuebersicht und Kundendetails deklarieren. Kommentieren wir diese wieder ein, werden die Klassen als Fehler markiert. Also fügen wir zunächst zwei leere Seite-Klassen namens Kundenuebersicht.xaml und Kundendetails.xaml hinzu, kopieren den XAML-Code der beiden Elemente aus dem C#-Projekt in die neuen Elemente und kümmern uns dann um den C#-Code, den wir übersetzen lassen und dann in die Code behind-Klasse des VB-Projekts kopieren. Hier wird dann in der Klasse Kundenuebersicht.xaml.vb zunächst das Fehlen der Klasse KundeEventArgs bemängelt. Diese fügen wir dann als neue VB-Klasse hinzu und übertragen die übersetzten Anweisungen der entsprechenden Klasse des C#-Projekts in diese Klasse.

Danach erledigen wir das Gleiche für die Seite-Klasse Kundendetails.xaml, was ohne weitere Fehlermeldungen gelingt. Nun wird es Zeit, die Methoden für die beiden Schaltflächen btnKundenuebersicht und btnNeuerKunde des Ribbons des Fensters MainWindow wieder komplett von Kommentarzeichen zu befreien. Das Gleiche gilt für alle weiteren Elemente, die wir in der Region Kunde zusammengefasst haben. Hier gibt es allerdings wieder ein paar Fehlermeldungen (siehe Bild 12).

Es gibt ein paar Probleme mit den Ereignissen.

Bild 12: Es gibt ein paar Probleme mit den Ereignissen.

Es stellt sich heraus, dass die Übersetzung des C#-Codes nach VB nicht perfekt ist. Das ist aber auch nicht zu erwarten, und somit beheben wir die wenigen verbleibenden Fehler von Hand. In diesem Fall können wir nicht einfach der Eigenschaft ItemDoubleClicked der Variablen kundenuebersicht den neuen Eventhandler zuweisen, sondern müssen dies mit der AddHandler-Methode erledigen. Diese Zeile hat einen Fehler gemeldet:

'kundenuebersicht.ItemDoubleClicked += New Kundenuebersicht.EventHandlerItemDoubleClicked(AddressOf OnKundeDoubleClicked)

Wir ersetzen sie durch die folgende Zeile, welche die AddHandler-Methode nutzt und als ersten Parameter das Ereignis und als zweiten die auszuführende Methode übergibt:

AddHandler kundenuebersicht.ItemDoubleClicked, AddressOf OnKundeDoubleClicked

Das Gleiche erledigen wir für die folgende Anweisung:

kundenuebersicht.NewItem += New Kundenuebersicht.EventHandlerNewItem(AddressOf OnNewKunde)

Hier lautet die Änderung wie folgt:

AddHandler kundenuebersicht.NewItem, AddressOf OnNewKunde

Auf die gleiche Weise wandeln wir die übrigen Zeilen zum Abonnieren von Ereignismethoden um.

Converter und Namespace

Zu einem Problem konnten wir keine Lösung finden: Die Anwendung enthält eine Converter-Klasse namens PercentageConverter, die in einem Unterordner namens Converter liegt. Diesen referenzieren wir auf der Seite BestellpositionDetails.xaml wie folgt:

<Page x:Class="Bestellverwaltung.BestellpositionDetails" ... >
     <Page.Resources>
         ....
         <local:PercentageConverter x:Key="Percentage" />
     </Page.Resources>
     ...
</Page>

Den Converter haben wir in der Klassendatei PercentageConverter.vb wie folgt angelegt:

             ...

Die Klasse gehört also zum Namespace Bestellverwaltung und sollte somit auch verfügbar sein. Allerdings liefert die Anwendung erst keinen Fehler mehr, wenn wir die Klasse PercentageConverter aus dem Namespace entfernen.

Zusammenfassung und Ausblick

Damit haben wir unsere Beispielanwendung von C# nach Visual Basic migriert. Die Details der Migration und die wichtigsten Unterschiede zwischen C# und Visual Basic schauen wir uns in der Artikelreihe Von C# zu Visual Basic an.

Bitte geben Sie die Zeichenfolge in das nachfolgende Textfeld ein

Die mit einem * markierten Felder sind Pflichtfelder.

Ich habe die Datenschutzbestimmungen zur Kenntnis genommen.