VB.NET Input Dialog

VB.NET Input Dialog

VB.NET Input Dialog

In VB.NET einen Input Dialog zu erstellen ist verglichen mit anderen Sprachen und vor allem deren Designer-Tools relativ einfach.

Sie sind Bestandteil von fast jedem Programm und jeder von uns nutzt Sie so gut wie täglich: Eingabefenster, oder in Programmierer-Jargon anders ausgedrückt: Input Dialogs.

Von den eher komplexeren Eingabemöglichkeiten mit Adressdaten und Berechnungen, bis hin zu der simpleren InputBox die ich in diesem Beitrag erläutere ist alles dabei.

Input Dialog – Szenario

In dem kleinen Beispiel, Welches ich Dir näher bringen möchte, zeige ich Dir einen Dialog, mit dessen Hilfe Du Adressdaten eingeben und entgegennehmen kannst.

Diese Adressdaten werden natürlich sauber in einer eigenen Klasse, bzw. dann deren Instanz gekapselt.

Du wirst sehen, wie Du den Dialog – also die Form – mit verschiedenen Dialog-Results schließen und Diese auswerten kannst.

Dabei gehe ich einmal den automatisierten Weg über einen Button DialogResult-Eigenschaft und andererseits einen manuellen Weg, da wir vorher noch einige Prüfungen durchführen werden.

Code – VB.NET Input Dialog

In diesem Abschnitt erkläre ich den Code zu meinem VB.NET Input Dialog Beispiel:

Country-Klasse

Diese Klasse steht für ein jeweiliges Land, Welches wir durch den Namen und dem Iso-Code darstellen.

Public Class Country
    Implements ICloneable

    Public Property Name As String

    Public Property Iso As String

    Sub New()
        Name = ""
        Iso = ""
    End Sub

    Sub New(name As String, iso As String)
        Me.Name = name
        Me.Iso = iso
    End Sub

    Public Overrides Function ToString() As String
        Return $"{Name} ({Iso})"
    End Function

    Public Function Clone() As Object Implements ICloneable.Clone
        Dim instance = New Country()
        With instance
            .Name = Name
            .Iso = Iso
        End With
        Return instance
    End Function

End Class

Eigenschaften

Name

In dieser Eigenschaft speichern wir den Namen des jeweiligen Landes, z. B. Deutschland.

Iso

Hier kommt der Iso-Code des Landes rein, z. B. „DE“ für Deutschland.

Konstruktoren

new

Ein leerer Konstruktor, um ein „leeresLand zu erstellen.

new(name, iso)

Der Konstruktor, um ein Land mit vorhandenen Informationen – also Name und Iso-Codezu erstellen.

Methoden

ToString

Damit wir das Land einfach und in einer lesbaren Form darstellen können.

Findet zum Beispiel in der ComboBox, oder einem DataGridView Anwendung, wenn kein expliziter DisplayMember festgelegt wurde.

Clone

Eine Methode, um ein Land ganz einfach und schnell kopieren/klonen zu können.

Ist analog zum Interface/zu der Schnittstelle namens ICloneable implementiert.

Address-Klasse

In dieser Klasse kapseln wir die nötigen Informationen zu einer jeweiligen Adresse.

Natürlich könnte man auch auf die einzelnen TextBoxen der Dialog-Form zugreifen, allerdings ist dies meiner Meinung nach keine saubere Herangehensweise.

Public Class Address
    Implements ICloneable

    Public Property Name As String

    Public Property Street As String

    Public Property HouseNo As String

    Public Property Zip As String

    Public Property City As String

    Public Property Country As Country

    Sub New()
        Name = ""
        Street = ""
        HouseNo = ""
        Zip = ""
        City = ""
        Country = Nothing
    End Sub

    Sub New(name As String, street As String, houseNo As String, zip As String, city As String, country As Country)
        Me.Name = name
        Me.Street = street
        Me.HouseNo = houseNo
        Me.Zip = zip
        Me.City = city
        Me.Country = country
    End Sub

    Public Function Clone() As Object Implements ICloneable.Clone
        Dim instance = New Address()
        With instance
            .Name = Name
            .Street = Street
            .HouseNo = HouseNo
            .Zip = Zip
            .City = City
            .Country = CType(Country.Clone(), Country)
        End With
        Return instance
    End Function

    Public Overrides Function ToString() As String
        Dim newLine = Environment.NewLine
        Return $"{Name}{newLine}
                {Street} {HouseNo}{newLine}
                {Zip} {City}{newLine}
                {Country.Name}"
    End Function

End Class

Eigenschaften

Folgende Eigenschaften habe ich für die Address-Klasse definiert

Name

Der Empfänger Name, z. B. Max Mustermann

Street

Die Straße der Adresse

HouseNo

Jeweilige Hausnummer der Adresse

Zip

Die Postleitzahl des Ortes

City

Der Ort bzw. die Stadt selbst, könnte man auch allgemeiner „Place“ nennen..

Country

Das Land, Welches in der Adresse festgelegt ist

Konstruktoren

Hier erkläre ich die Konstruktoren der Klasse

new

Es gibt einen leeren Konstruktor, um die Adresse auch „leer“ erstellen und ggf. später befüllen zu können, wie bei der Clone-Implementierung.

new(name, street, houseNo, zip, city, country)

Dieser Konstruktor soll das komfortable Anlegen von Address-Instanzen via Informationen erleichtern.

Methoden

Clone

Diese Methode ist analog der ICloneable-Schnittstelle implementiert worden und dient praktisch dem einfachen Kopieren von Adressen.

ToString

Hier bieten wir dem Nutzer der Address-Klasse eine einfache Möglichkeit, die Adresse in gängiger, lesbarer Form als String darzustellen.

dlgAddress-Klasse – VB.NET Input Dialog

VB.NET Input Dialog Beispiel dlgAddress
VB.NET Input Dialog Beispiel dlgAddress

Mit Hilfe der dlgAddress-Klasse stellen wir die Funktionalität eines Adress-Dialogs bereit.

Imports System.ComponentModel

Public Class dlgAddress

    Public ReadOnly Property Required As Boolean

    Public Property Countries As BindingList(Of Country)

    Public Property Address As Address
        Get
            Dim name = tbName.Text.Trim()
            Dim street = tbStreet.Text.Trim()
            Dim houseNo = tbHouseNo.Text.Trim()
            Dim zip = tbZip.Text.Trim()
            Dim city = tbCity.Text.Trim()
            Dim country = CType(CType(cbbCountry.SelectedItem, Country).Clone(), Country)
            Return New Address(name, street, houseNo, zip, city, country)
        End Get
        Set(value As Address)
            With value
                tbName.Text = value.Name
                tbStreet.Text = value.Street
                tbHouseNo.Text = value.HouseNo
                tbZip.Text = value.Zip
                tbCity.Text = value.City
                Dim countryGiven = value.Country IsNot Nothing
                Dim country As Country = Nothing
                If countryGiven Then
                    country = Countries.SingleOrDefault(Function(x) x.Iso.ToLower() = value.Country.Iso.ToLower())
                End If
                cbbCountry.SelectedItem = country
            End With
        End Set
    End Property

    Private Property ValidationSucceeded As Boolean

    Sub New()
        InitializeComponent()
        Required = False
        PopulateCountries()
    End Sub

    Sub New(required As Boolean)
        InitializeComponent()
        Me.Required = required
        PopulateCountries()
    End Sub

    Private Sub PopulateCountries()
        Dim germany = New Country("Deutschland", "DE")
        Dim austria = New Country("Österreich", "AU")
        Dim swiss = New Country("Schweiz", "CH")
        Countries = New BindingList(Of Country) From {
            germany, austria, swiss
        }
        With cbbCountry
            .DisplayMember = "Name"
            .ValueMember = "Iso"
            .DataSource = Countries
        End With
    End Sub

    Private Sub btnOk_Click(sender As Object, e As EventArgs) Handles btnOk.Click
        ValidationSucceeded = ValidateInputs()
        If Not ValidationSucceeded Then
            MessageBox.Show("Bitte füllen Sie alle Felder aus!", "Adresse eingeben", MessageBoxButtons.OK, MessageBoxIcon.Warning)
            Return
        End If
        DialogResult = DialogResult.OK
    End Sub

    Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
        If Not Required Then
            DialogResult = DialogResult.Cancel
            Return
        End If
        ShowRequiredAlert()
    End Sub

    Private Sub dlgAddress_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
        If Required AndAlso Not ValidationSucceeded Then
            ShowRequiredAlert()
            e.Cancel = True
        End If
    End Sub

    Private Sub ShowRequiredAlert()
        MessageBox.Show("Bitte geben Sie eine Adresse ein!", "Adresse eingeben", MessageBoxButtons.OK, MessageBoxIcon.Warning)
    End Sub

    Private Function ValidateInputs() As Boolean
        If String.IsNullOrEmpty(tbName.Text.Trim()) Then
            Return False
        End If
        If String.IsNullOrEmpty(tbStreet.Text.Trim()) Then
            Return False
        End If
        If String.IsNullOrEmpty(tbHouseNo.Text.Trim()) Then
            Return False
        End If
        If String.IsNullOrEmpty(tbZip.Text.Trim()) Then
            Return False
        End If
        If String.IsNullOrEmpty(tbCity.Text.Trim()) Then
            Return False
        End If
        If cbbCountry.SelectedItem Is Nothing Then
            Return False
        End If
        Return True
    End Function

End Class

Eigenschaften

Required

Eine Readonly Property um beim Instanziieren des Dialoges festzulegen, ob Dieser erforderlich ist, oder nicht.

Sie kann und soll in meinem Beispiel anschließend nicht mehr geändert werden.

Countries

Eine Liste von verschiedenen Ländern, die wir testweise im Konstruktor befüllen, würde normalerweise natürlich aus einer Art Service/Schnittstelle mit Hilfe von Dependency-Injection kommen.

Address

Hier haben wir eine manuell implementierte Property, also das Gegenteil von Auto-Properties und somit mit einem eigens definierten Getter und Setter.

Wenn der Getter aufgerufen wird, soll aus der grafischen Oberfläche ein neues AddressObjekt erzeugt und wiedergegeben werden.

Beim Aufruf des Setters wird der Weg praktisch umgedreht, also die Werte aus dem übergebenen Wert, werden in die Controls geladen.

ValidationSucceeded

Bei dieser Eigenschaft handelt es sich praktisch um einen internen Zwischenspeicher, ob die Validierung der Inputs geklappt hat.

Konstruktoren

new

Der leere Konstruktor erstellt eine neue Instanz des Dialoges, mit dem Required-Member auf False und kümmert sich anschließend um die Countries.

new(required)

Dieser Konstruktor macht das Gleiche wie der Leere, gibt aber die Möglichkeit, den Required-Member frei zu bestimmen.

Methoden

PopulateCountries

Die PopulateCountries-Methode kümmert sich wie der Name schon sagt um die Befüllung der Country-bezogenen Daten.

Ebenso kümmert Sie sich um die Anzeige in der ComboBox, was eventuell auch in eine eigene Sub passen könnte.

btnOk_Click

Mit dieser Methode prüfen wir, ob die Validierung der Inputs funktioniert hat und speichern dies in der dafür vorgesehenen privaten Eigenschaft zwischen.

Falls die Validierung hier nicht funktioniert hat, geben wir eine passende Meldung an den Nutzer aus und verlassen die aktuelle Ausführung im Sinne des Early-Return-Prinzips mit Return.

Wenn die Validierung funktioniert hat, schließen wir den Dialog mit dem DialogResult „OK“.

btnCancel_Click

Dies ist die Methode, die neben dem „X“ oben rechts für das Abbrechen des Dialoges zuständig ist.

Allerdings funktioniert, bzw. erlauben wir beides nur dann, wenn die Eingabe des Dialoges nicht zwangsweise durch die Required-Eigenschaft erforderlich ist.

Ansonsten zeigen wir eine Meldung mit einer Methode an, um den Code an anderer Stelle nicht doppeln zu müssen.

dlgAddress_Closing

In dieser Methode prüfen wir, ob das Ausfüllen des Dialoges erforderlich ist und ob die Validierung fehlgeschlagen ist.

Falls beides eintrifft, brechen wir das Schließen des Formulars ab und zeigen dem Nutzer eine entsprechende Meldung.

ShowRequiredAlert

Dies ist eine Methode zum Anzeigen einer „Required“-Meldung, Welche duplicated Code vermeiden soll.

ValidateInputs

Diese Funktion liefert einen Wert zurück und schaut, ob die Validierung der jeweiligen Inputs funktioniert hat.

Hier wäre eine getrennte Methode um den duplicated Code zu verringern auch sinnvoll, allerdings möchte ich nicht alles für Anfänger noch weiter verkomplizieren.

Dieser Code könnte wie folgt aussehen:

Private Function ValidateTextBoxes(ParamArray textboxes As TextBox())
    For Each tb In textboxes
        Dim text = tb.Text.Trim()
        If String.IsNullOrEmpty(text) Then
            Return False
        End If
    Next
    Return True
End Function

Private Function ValidateInputs() As Boolean
    Dim textBoxesOk = ValidateTextBoxes(tbName, tbStreet, tbHouseNo, tbZip, tbCity)
    If Not textBoxesOk Then
        Return False
    End If
    If cbbCountry.SelectedItem Is Nothing Then
        Return False
    End If
    Return True
End Function

frmMain-Klasse

VB.NET Input Dialog Beispiel frmMain
VB.NET Input Dialog Beispiel frmMain

Diese Klasse stellt praktisch das Start– und Hauptformular unserer Anwendung dar.

Mit Hilfe des einen Buttons zeigen wir unseren gebauten Adress-Dialog an und holen uns bei Erfolg die jeweilige Adresse in gekapselter Form – also als Instanz der Address-Klasse.

Beim zweiten Beispiel, also mit dem zweiten Button, verfahren wir ähnlich, nur das wir den Nutzer da dann praktisch „zwingen“ können, falls eine Adresseingabe erforderlich ist.

Public Class frmMain

    Private Sub btnShowDialog_Click(sender As Object, e As EventArgs) Handles btnShowDialog.Click
        Using dialog As New dlgAddress()
            Dim result = dialog.ShowDialog()
            If result <> DialogResult.OK Then
                Return
            End If
            Dim address = dialog.Address
            ' do something with address
        End Using
    End Sub

    Private Sub btnShowRequiredDialog_Click(sender As Object, e As EventArgs) Handles btnShowRequiredDialog.Click
        Dim isDialogRequired = True
        Using dialog As New dlgAddress(isDialogRequired)
            Dim result = dialog.ShowDialog()
            ' as we force the dialog to be completed successfully..
            Dim address = dialog.Address
            ' do something with address
        End Using
    End Sub

End Class

Methoden

btnShowDialog_Click

Das ist der Click-Ereignishandler für den Button, Welcher die Arbeit für das erste Dialog-Fenster übernimmt.

btnShowRequiredDialog_Click

Der zweite ClickEreignishandler, Welcher die Arbeit des zweiten Buttons und den „Ausfüll-Zwang“ beinhaltet.

Downloads

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.