Die Community zu .NET und Classic VB.
Menü

Steuerelementfelder in VB2005

 von 

Einleitung 

Der Designer aus Visual Basic 6 bietet die Möglichkeit des bequemen Zusammenfassens mehrerer gleichartiger Steuerelemente zu Steuerelementfeldern über die Festlegung der Index-Eigenschaft. In Visual Basic 2005 scheint diese Funktionalität auf den ersten Blick nicht mehr vorhanden zu sein. Dies ist im unterschiedlichen Modell für die Verwaltung von Steuerelementen begründet: Während unter Visual Basic 6 Steuerelemente besondere Sprachbestandteile sind, die unabhängig vom Programmcode in Formulardateien gespeichert werden, handelt es sich in der .NET-Technologie dabei um ganz normale Objekte, die mit Quellcodeanweisungen erstellt und verwaltet werden. Für mit dem Visual Studio-Designer aufs Formular gezeichnete Steuerelemente wird der zugehörige Code in einer auf .Designer.vb endenden Datei automatisch erstellt, es ist jedoch ohne Probleme möglich und üblich, selbst Steuerelementobjekte zu erstellen. In diesem Tutorial soll schrittweise erläutert werden, wie Steuerelemente am einfachsten erstellt und in Containern gespeichert werden können.

Erstellen des Projekts  

In diesem Artikel wird ein einfaches Projekt mit einem einzelnen Formular verwendet, welches beispielsweise durch Auswählen der Vorlage Windows-Anwendung im Dialogfeld Neues Projekt erstellt werden kann. Sämtlicher dargestellter Quelltext gehört zum Code des Formulars. Es werden Klassen aus den Namensräumen System, System.Collections.Generic, System.Drawing und System.Windows.Forms verwendet, die hier als importiert angenommen werden.

Erstellen von einzelnen Steuerelementen  

Im ersten Schritt wird zunächst eine einzelne Schaltfläche erzeugt und dem Formular hingefügt. Der Code kann an jeder Stelle eingefügt werden, beispielsweise im Ereignisbehandlungsroutine des Load-Ereignisses des Formulars.

Dim NewButton As New Button
NewButton.Name = "NewButton"
NewButton.Text = "&Klick mich!"
NewButton.Location = New Point(50, 50)
NewButton.Size = New Size(200, 40)
Controls.Add(NewButton)

Listing 1

Was geschieht hier? In der ersten Zeile wird eine neue Schaltfläche, d.h. ein Objekt der Klasse System.Windows.Forms.Button, erzeugt und der lokalen Variablen NewButton zugewiesen. In den vier folgenden Zeilen werden vier essentielle Eigenschaften gesetzt. Dies ist zwar zum fehlerlosen Ausführen des Codes nicht nötig, aber sehr sinnvoll, da die erstellte Schaltfläche in den allermeisten Fällen einen Beschriftungstext, eine Position auf dem Formular und eine Größe haben soll. Ohne die Festlegung der Text-Eigenschaft ist keine Beschriftung vorhanden; wird auf die Festlegung der Location- und Size-Eigenschaften verzichtet, so zeigt Visual Basic die neu erstellte Schaltfläche in der linken oberen Ecke mit einer Standardgröße an. Statt der Festlegung von Location und Size können natürlich auch andere Möglichkeiten zur Festlegung der Steuerelementbegrenzungen, z.B. die SetBounds-Methode, verwendet werden. Die Name-Eigenschaft wird festgelegt, damit auf das Steuerelement mit der Controls- Auflistungsobjektes zugegriffen werden kann. Mit der letzten Zeile wird die Schaltfläche dem Formular hinzugefügt. Soll sie nicht zum Formular, sondern zu einem Containersteuerelement, z.B. einem Panel, gehören, so ist die Add- Methode des Controls-Objekts des entsprechenden Containers zu benutzen, beispielsweise Panel1.Controls.Add.

Behandlung von Ereignissen  

Bis hierhin ist die erzeugte Schaltfläche noch nicht besonders sinnvoll, da sie nicht auf Benutzereingaben reagieren kann. Es muss deshalb Code für die Behandlung von Ereignissen hinzugefügt werden. Dies ist nicht so bequem wie bei im Designer gezeichneten Steuerelementen, wo beispielsweise bei Schaltflächen eine Ereignisbehandlungsroutine für das Click-Ereignis durch einen schlichten Doppelklick auf das Steuerelement eingefügt wird. Stattdessen wird bei der manuellen Erstellung von Steuerelementen die Registrierung einer Ereignisbehandlungsroutine unter Zuhilfenahme einer AddHandler-Anweisung bewerkstelligt:

Dim NewButton As New Button
NewButton.Name = "NewButton"
NewButton.Text = "&Klick mich!"
NewButton.Location = New Point(50, 50)
NewButton.Size = New Size(200, 40)
AddHandler NewButton.Click, AddressOf ButtonClick
Controls.Add(NewButton)

Listing 2

Die hier benutze Funktion ButtonClick muss natürlich ebenfalls definiert werden, und zwar mit der durch das fragliche Ereignis vorgegebenen Signatur:
Private Sub ButtonClick(sender As Object, e As EventArgs)
MessageBox.Show("Hello from " & CType(sender, Button).Name)
End Sub

Listing 3

Nach einem Klick auf die Schaltfläche springt ein Nachrichtendialogfeld auf, das eine Nachricht sowie den Namen der angeklickten Schaltfläche anzeigt, womit auch illustriert wird, wie auf den Auslöser des Ereignisses zugegriffen werden kann: Das Argument sender, welches nach der .NET-Ereignisbehandlungskonvention einen Verweis auf das das Ereignis auslösende Objekt darstellt, muss mit CType in den benötigten Zieltyp konvertiert werden. Das funktioniert natürlich nur, wenn der Typ des auslösenden Steuerelements in den Zieltyp konvertiert werden kann, andernfalls schlägt die Umwandlung mit einer Ausnahme fehl. Wird eine einzige Ereignisbehandlungsroutine für mehrere unterschiedliche Steuerelemente benutzt, sollte deshalb mit dem TypeOf-Operator oder einer ähnlichen Technik zunächst der dynamische Typ des sender-Parameters überprüft werden.

Verwendung einer Klassenvariablen  

Bis jetzt wurde eine lokale Variable zum Referenzieren des Steuerelements benutzt. Oft bietet es sich jedoch an, eine Klassenvariable dafür zu verwenden, um auch außerhalb der erstellenden Prozedur einfach (d.h. ohne Verwendung der Controls-Auflistung) auf das Steuerelement zugreifen zu können. Hierbei bieten sich mehrere Varianten an:

  • Private NewButton As Button:
    Hierbei wird nur die Variable deklariert. Zuweisung und Ereignisbehandlung müssen im Code geschehen.
  • Private NewButton As New Button:
    Das Objekt wird bei Erstellung des Formulars instanziert, sodass dies später nicht mehr nötig ist.
  • Private WithEvents NewButton As Button:
    Die Ereignisbehandlung muss nicht durch AddHandler, sondern kann auch durch die einfachere, aber auch unflexiblere Handles-Klausel geschehen: Private Sub ButtonClick(sender As Object, e As EventArgs) Handles NewButton.Click

Steuerelementfelder  

Wie durch diese Ausführungen erkannt werden konnte, läuft das Erstellen von Steuerelementen in .NET wesentlich anders und vor allem deutlich flexibler als in früheren Versionen von Visual Basic ab. Wie in allen anderen Punkten, so müssen auch hier die bisherigen Programmierkonzepte gründlich überdacht werden, da die zwei Sprachen auf unterschiedlichen Prinzipien basieren. Eine Eins-zu-eins-Umsetzung von Steuerelementfeldern in Visual Basic 2005 ist deshalb nicht möglich. Der größte Unterschied für den Programmierer besteht darin, dass es keinerlei Unterstützung des Designers für Steuerelementfelder mehr gibt. Auch die Positionierung von Steuerelementen muss deshalb von Hand erfolgen. Die Frage, wie eine Anzahl gleichartiger Steuerelemente erstellt und verwaltet werden, muss außerdem für jeden Fall neu beantwortet werden. Im Folgenden sollen nun einige typische Fälle besprochen werden.

  • Mehrere gleichartige Steuerelemente, die weder Benutzerinteraktion noch späteren Zugriff benötigen, beispielsweise Bezeichnungsfelder, sollen erstellt werden: Hier genügt die einfache Erstellung und Hinzufügung von Steuerelementobjekten wie im ersten Beispiel, meist sogar ohne Zuweisung der Name-Eigenschaft, da kein späterer Zugriff mehr nötig ist.
  • Steuerelemente, auf die nach der Erstellung noch zugegriffen werden muss: Dafür sind die im Framework vorhandenen Containerklassen in den Namensräumen System.Collections.Generic und System.Collections gut geeignet. Sie erlauben sehr flexible Verwaltung, z.B. Hinzufügen und Entfernen von Steuerelementen zu beliebigen Zeitpunkten.
  • Steuerelemente, die auf Benutzerinteraktionen reagieren müssen: Da die Handles-Klausel nur bei einzelnen Objekten, nicht aber bei Containerklassen funktioniert, muss hier auf die oben beschriebene AddHandler-Anweisung zurückgegriffen werden.
Das beigelegte Projekt enthält ein komplettes, funktionierendes Beispiel. Der Benutzer kann Steuerelementgruppen, die jeweils aus einem Textfeld und einer Schaltfläche zum Entfernen der Gruppe bestehen, nach Belieben erzeugen und entfernen. Wenn er in die Textfelder Zahlen eingibt, wird die Summe aller dieser Zahlen bestimmt. Eine Containervariable wird nur für die Textfelder angelegt. Damit aus dem Ereignisbehandlungscode der zum Entfernen dienenden Schaltflächen auf das jeweils zugehörige Textfeld zugegriffen werden kann, wird ein Verweis auf dieses in der Tag- Eigenschaft der Schaltflächen gespeichert. Hier der komplette Code:
Imports System
Imports System.Collections.Generic
Imports System.Windows.Forms


Public Class Beispiel
    Private ReadOnly mEingabefelder As New LinkedList(Of TextBox)

    Private Sub Hinzufügen(ByVal sender As Object, ByVal e As EventArgs) Handles btnHinzufügen.Click
        Static Position As Integer = 40
        Position += 40
        Dim Eingabefeld As New TextBox
        Eingabefeld.SetBounds(20, Position, 100, 30)
        Eingabefeld.Text = "0"
        Eingabefeld.TextAlign = HorizontalAlignment.Right
        AddHandler Eingabefeld.TextChanged, AddressOf Summieren
        mEingabefelder.AddLast(Eingabefeld)
        Controls.Add(Eingabefeld)
        Dim Schaltfläche As New Button
        Schaltfläche.SetBounds(140, Position, 100, 30)
        Schaltfläche.Text = "Entfernen"
        Schaltfläche.Tag = Eingabefeld
        AddHandler Schaltfläche.Click, AddressOf Entfernen
        Controls.Add(Schaltfläche)
    End Sub

    Private Sub Entfernen(ByVal sender As Object, ByVal e As EventArgs)
        Dim Schaltfläche As Button = DirectCast(sender, Button)
        Dim Eingabefeld As TextBox = DirectCast(Schaltfläche.Tag, TextBox)
        Controls.Remove(Eingabefeld)
        Controls.Remove(Schaltfläche)
        mEingabefelder.Remove(Eingabefeld)
        Summieren(sender, e)
    End Sub

    Private Sub Summieren(ByVal sender As Object, ByVal e As EventArgs)
        Dim Summe As Double = 0
        For Each Eingabefeld As TextBox In mEingabefelder
            Dim Zahl As Double = 0
            If Double.TryParse(Eingabefeld.Text, Zahl) Then Summe += Zahl
        Next
        txtSumme.Text = Summe.ToString()
    End Sub

End Class

Listing 4: Komplettes Beispiel

In diesem sehr einfachen Beispiel werden neu erzeugte Steuerelementgruppen einfach immer weiter unten angehängt; beim Entfernen bleiben die sich darunter befindlichen Gruppen an ihrem Platz, wodurch Lücken entstehen. Bei ernsthaften Anwendungen würde dies selbstverständlich anders geregelt werden, was aber der Funktionalität des Beispiels keinen Abbruch tut. Statt der verketteten Liste können natürlich, je nach Anwendung, andere Containerklassen eingesetzt werden.

Fazit  

Es ist mir hoffentlich gelungen, in diesem kurzen Artikel die grundlegenden Ideen und Vorgehensweisen zum Erstellen und Verwalten dynamisch generierter Steuerelemente herauszuarbeiten. Die aus Visual Basic 6 bekannten Steuerelementfelder existieren nicht mehr und müssen durch neue, objektorientierte Denkweisen ersetzt werden, was einerseits die Abkehr von bekannten Vorgehensweisen erzwingt, andererseits neue Möglichkeiten eröffnet.

Beispielprojekt  

Das angesprochene VB2005-Projekt:

Download 

Ihre Meinung  

Falls Sie Fragen zu diesem Tutorial haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.