VB NET Formular automatisch ausfüllen (Winforms)

VB.NET Form automatisch ausfüllen
VB.NET Form automatisch ausfüllen

VB.NET Formulare automatisch ausfüllen!

Ein VB NET Formular automatisch ausfüllen zu lassen wäre vermutlich für jeden „Windows Forms“ geprägten Entwickler eine Erleichterung. Man designt die Form seiner Wahl und möchte natürlich bei Aufruf die notwendigen Daten anzeigen. Besonders beim Flow aus diversen Suchmasken heraus ist es normal, dass man eine Detail-Ansicht mit entsprechenden Daten aufruft.

Wie es meistens ist..

Am besten wäre es natürlich, wenn man dem Formular direkt sagen könnte: „Hey, die Daten findest Du dort“. Mit modernen Mitteln wie in der WPF (Windows Presentation Foundation) ist dies durch Datenbindung eine gängige und vor allem einfache Praxis.

Dort findet man durch die saubere Trennung zwischen GUI und Daten eine simple und direkt in XAML implementierte Möglichkeit. In den guten alten Winforms findet man jedoch seltenst (jedenfalls aus meiner Erfahrung gesprochen) datengebundene Steuerelemente.

Monkey Work – ney, Automatisierung – yay!

Dort sieht es dann entgegengesetzt jeglicher Automatisierung eher so aus:

TextBox1.Text = "..."
TextBox2.Text = "..."
TextBox3.Text = "..."
TextBox4.Text = "..."
' ....

Eventuell entwickelt man wenigstens einigermaßen sauber und wählt passende Namen für die Textboxen:

tbFirstName.Text = "..."
tbLastName.Text = "..."
tbZip.Text = "..."
tbCity.Text = "..."
' ....

Schon besser, aber natürlich kann man sich schon vorstellen, dass dies nicht unbedingt das Gelbe vom Ei ist. Man wird auf diverse Probleme, bzw. Monkey-Work stoßen, Welche für Wartung und Co. nicht gerade vorteilhaft sind. Tonnenweise „duplicated Code“ und schon glatt eine Qual, wenn es bei einem Objekt mit 30 Properties heißt: „Hey, zeige die Daten mal an…“.

VB.NET Formulare ausfüllen Monkey Work
VB.NET Formulare ausfüllen Monkey Work

Nun ist man an einem Punkt, wo die bekannte Faulheit doch zum Vorteil sein und zu mehr Effizienz beitragen kann. Wie so häufig, haben wir als Entwickler die Möglichkeit uns gewisse (und vor allem wiederkehrende Aufgaben) zu vereinfachen. Not macht erfinderisch, richtig?

An die Zukunft denken

Je nachdem wie viel Planung und anschließenden Zeitaufwand man bereit ist zu investieren (nicht opfern!), wird die bevorstehende Arbeit beeinflussen. Man sollte meiner Meinung nach jedoch immer eins im Hinterkopf behalten: „Think twice, code once“! Leider arbeiten viele Entwickler auch gerne nach dem „Copy & Paste“-Prinzip, zur Not auch projektübergreifend.

Statt hier zukunftsorientiert zu denken, werden Aufgaben häufig nur akut und schnell gelöst. Auch wenn die Erledigung einiger Aufgaben ggf. am Anfang nervig und zeitaufwendig sind, können Sie einem später unfassbar viel Zeit ersparen. Dies gilt natürlich nicht nur für das aktuelle Projekt, sondern vermutlich auch noch für später anstehende Projekte und Problemstellungen.

Herangehensweise – VB NET Formular automatisch ausfüllen

Im nächsten Schritt machen wir uns einmal ein paar Gedanken bezüglich der Herangehensweise, die (Windows Forms)-Formulare automatisiert(er) auszufüllen. Auch wenn wir hier vermutlich noch keine volle Suite an Mini-Tools generieren werden, wird das meinerseits dargestellte Beispiel als Startschuss dienen können.

Jeder Entwickler im NET Bereich wird wohl immer wieder mal mit den guten alten Textboxen zu tun haben. Ich denke, dass dieses Steuerelement daher auch die erste zu bearbeitende Anlaufstelle sein sollte. Wenn man hingegen an Checkboxen, Listboxen und an die anderen Steuerelemente denkt, könnte es schon ein wenig komplexer werden.

Vielleicht werde ich dafür dann noch einmal einen getrennten Beitrag in Zukunft erstellen. Schauen wir einmal, wo mich die Beitrags-Reise, bzw. meine Schreib-Lust heute hinführt 😉.

Konkreter Ablauf

Wenn man sauber vorgeht, sollte man die Daten natürlich in irgendeiner sinnvollen Form vorliegen haben. Nach Möglichkeit gibt es hier also nicht z. B. 15 verschiedene Variablen, Welche dann im schlimmsten Fall noch „string1, string2, usw.“ heißen. Wir wollen ja im besten Fall mit relativ fest definierten Mustern arbeiten, um unsere Arbeit so einfach wie möglich zu gestalten.

Ich stelle mir einerseits eine bereits definierte Klasse als Daten-Container vor, andererseits könnte es sich auch um analog zugreifbare Daten wie bei einer DataRow handeln. Den konkreten Ablauf würde man kurz und knapp vielleicht so beschreiben: „Nimm dieses Ding hier und packe dessen Eigenschafts-Werte in die passenden Steuerelemente“.

Dabei könnte man entweder ausgehend vom Objekt, oder von der jeweiligen Form arbeiten, also Pseudocode mäßig so:

Für jede Eigenschaft im Objekt, finde die passende Textbox, trage den passenden Wert ein..

oder..

Für jede/s Textbox/Steuerelement auf dem Formular, finde im Ziel-Objekt die passende Eigenschaft und befülle Diese.

Eventuell könnte man hier auch noch für die Performance mit irgendeiner Art Cache arbeiten, oder je nach Situation die „Strategie“ (Anspielung Strategy-Pattern…) ändern. Ich werde es hier allerdings nicht weiter als nötig verkomplizieren, da dieses Beispiel nur als Inspiration dienen soll.

Code – VB NET Formular automatisch ausfüllen

VB.NET Formular automatisch ausfüllen mit Kundendaten
VB.NET Formular automatisch ausfüllen mit Kundendaten

Nachdem wir die Herangehensweise ein wenig durch Pseudocode dargestellt haben, starten wir auch direkt in den Code. Ich werde auf jeden Fall ein Modul verwenden, damit man den Code auch einfach für andere Projekte wiederverwenden kann. Alternativ könnte man natürlich auch eine getrennte Klassenbibliothek, ein NuGet-Paket, o. Ä. erstellen.

Mit gewissen neuen aus C# bekannten Features könnte man auch vielleicht in Visual Basic eine „Trait“ ähnelnde Verwendungsweise realisieren. Wie bekannt ist, ist Komposition ja zumeist besser, als Vererbung (Stichwort: „composition over inheritance“). „Traits“ kennt man zum Beispiel allzu gut aus der Web-Programmiersprache namens PHP, aber dazu vielleicht in einem anderen Beitrag mehr.

Das Modul

Erstelle nun im ersten Schritt ein neues Modul namens (z. B.) „modExtensions“ – auch hier verwende ich gerne eine kleine Konvention. Ich halte mich immer an ähnliche Bezeichnungen / Präfixe, wie z. B. „tb“ für eine Textbox, „cbb“ für eine Combobox, etc. Welchen Sinn das dann eventuell haben kann / wird, sehen wir unter anderem (und besonders) im heutigen Beitrag!

Da wir schon analog zum Modul geplant haben, eine Erweiterungsmethode zu verwenden, importieren wir direkt den „System.Runtime.CompilerServices“-Namespace.

Eine Fill-Methode – VB NET Formular automatisch ausfüllen

Durch den Import des zuvor genannten Namespaces, können wir dann das „Extension“-Attribut verwenden und unsere Methode namens z. B. „Fill“ damit bestücken.

Als nächstes definieren wir die beiden benötigten Parameter:

  • Die Form, bzw. dessen Steuerelemente, Welche befüllt werden sollen
  • Das Objekt, also eine jeweilige Instanz eines x-beliebigen Typs, Welches die Daten beinhaltet
Imports System.Runtime.CompilerServices

Module modExtensions

    <Extension()>
    Public Sub Fill(frm As Form, obj As Object)
        ' ...
    End Sub

End Module

Danach erfassen wir die Textboxen aus der „Controls“-Auflistung des Formulars, damit wir Diese anschließend verwenden können. Praktisch im gleichen Schritt, ziehen wir uns einfach auch direkt die Eigenschaften (Definitionen) des Daten-Objekts.

Das geht relativ einfach, also wie folgt:

Dim textBoxes = frm.Controls.OfType(Of TextBox)
Dim properties = obj.GetType().GetProperties()

Danach können wir die eben abgerufenen Textboxen einfach in einer „For Each“-Schleife durchlaufen und dann mit dem Befüllen der Eigenschaften beginnen. Im ersten Teil der Schleife prüfen wir, ob die jeweilige Textbox mit dem korrekten Prefix „tb“ betitelt wurde. Wir halten uns also an eine kleine, von uns festgelegte Konvention. Vielleicht sollte man dies auch durch ein eigenes Attribut konfigurierbar machen, jedoch verzichten wir der Einfachheit halber aktuell darauf. Falls die Textbox nicht mit „tb“ beginnt, ignorieren wir Sie aktuell einfach, sprich die Schleife springt in den nächsten Durchlauf.

Dim wrongPrefix = Not tb.Name.StartsWith("tb")
If wrongPrefix Then
    Continue For
End If

Der darauf folgende Teil prüft, ob wir eine Eigenschaft mit passendem Namen zur Textbox finden können. Ebenso checken wir, ob der Typ zur Textbox passt, es sich dabei also um einen String handelt.

Dim nameWithoutPrefix = tb.Name.Substring(2)
Dim matchingProperty = properties.SingleOrDefault(Function(x) x.Name = nameWithoutPrefix)
If matchingProperty Is Nothing OrElse matchingProperty.PropertyType IsNot GetType(String) Then
    Continue For
End If

Der letzte und wichtigste Part – also nach dem Motto „das Beste kommt zum Schluss“ – ist, die Text-Eigenschaft der Textbox zu setzen:

tb.Text = matchingProperty.GetValue(obj).ToString()

Dazu verwenden wir die „GetValue“-Funktion der „PropertyInfo“-Klasse, um an den hinterlegten Wert der Eigenschaft zu kommen.

Kompletter Code

Wie immer fasse ich hier am Ende des Beitrages den kompletten Code zusammen.

Imports System.Runtime.CompilerServices

Module modExtensions

    <Extension()>
    Public Sub Fill(frm As Form, obj As Object)
        Dim textBoxes = frm.Controls.OfType(Of TextBox)
        Dim properties = obj.GetType().GetProperties()

        For Each tb In textBoxes

            Dim wrongPrefix = Not tb.Name.StartsWith("tb")
            If wrongPrefix Then
                Continue For
            End If

            Dim nameWithoutPrefix = tb.Name.Substring(2)
            Dim matchingProperty = properties.SingleOrDefault(Function(x) x.Name = nameWithoutPrefix)
            If matchingProperty Is Nothing OrElse matchingProperty.PropertyType IsNot GetType(String) Then
                Continue For
            End If

            tb.Text = matchingProperty.GetValue(obj).ToString()
        Next
    End Sub

End Module
using System;
using System.Windows.Forms;

namespace AutoFillFormCS
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnAutoFill_Click(object sender, EventArgs e)
        {
            var customer = new Customer()
            {
                Company = "Nice ltd.",
                FirstName = "Max",
                LastName = "Random",
                Street = "The street",
                HouseNo = "11a"
            };
            this.Fill(customer);
        }
    }
}

Weiterführende Links

Downloads

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.