Das Weglassen von Kontroll-Arrays aus VB.NET ist eine Herausforderung für diejenigen, die sich mit Arrays befassen.
Wenn Sie auf die VB6-Kompatibilitätsbibliothek verweisen, befinden sich darin Objekte, die sich wie Steuerfelder verhalten. Um zu sehen, was ich meine, verwenden Sie einfach den VB.NET-Aktualisierungsassistenten mit einem Programm, das ein Steuerfeld enthält. Der Code ist wieder hässlich, aber es funktioniert. Die schlechte Nachricht ist, dass Microsoft nicht garantiert, dass die Kompatibilitätskomponenten weiterhin unterstützt werden, und Sie sollten sie nicht verwenden.
Der VB.NET-Code zum Erstellen und Verwenden von "Steuerfeldern" ist viel länger und komplexer.
Laut Microsoft muss eine "einfache Komponente, die die Funktionen von Steuerfeldern dupliziert", erstellt werden, um die Funktionen von VB 6 zu verbessern.
Sie benötigen sowohl eine neue Klasse als auch ein Hosting-Formular, um dies zu veranschaulichen. Die Klasse erstellt und zerstört tatsächlich neue Labels. Der vollständige Klassencode lautet wie folgt:
Öffentliche Klasse LabelArray
Übernimmt System.Collections.CollectionBase
Privates schreibgeschütztes HostForm als _
System.Windows.Forms.Form
Öffentliche Funktion AddNewLabel () _
Als System.Windows.Forms.Label
'Erstellen Sie eine neue Instanz der Label-Klasse.
ALabel als neues System verdunkeln.Windows.Forms.Label
'Fügen Sie das Etikett der Sammlung hinzu
'interne Liste.
Me.List.Add (aLabel)
'Fügen Sie das Label der Controls-Sammlung hinzu
'des Formulars, auf das im Feld HostForm verwiesen wird.
HostForm.Controls.Add (aLabel)
'Festlegen der Anfangseigenschaften für das Label-Objekt.
aLabel.Top = Count * 25
aLabel.Width = 50
aLabel.Left = 140
aLabel.Tag = Me.Count
aLabel.Text = "Label" & Me.Count.ToString
Geben Sie aLabel zurück
Funktion beenden
Public Sub New (_
ByVal host As System.Windows.Forms.Form)
HostForm = Host
Me.AddNewLabel ()
End Sub
Öffentliche ReadOnly-Standardeigenschaft _
Item (ByVal Index As Integer) As _
System.Windows.Forms.Label
Bekommen
Rückgabe CType (Me.List.Item (Index), _
System.Windows.Forms.Label)
End Get
Eigenschaft beenden
Öffentliches Sub entfernen ()
'Vergewissern Sie sich, dass ein Etikett entfernt werden muss.
If Me.Count> 0 Then
'Entfernen Sie das zuletzt zum Array hinzugefügte Label
'aus dem Host-Formular steuert Sammlung.
'Beachten Sie die Verwendung der Standardeigenschaft in
'Zugriff auf das Array.
HostForm.Controls.Remove (Me (Me.Count - 1))
Me.List.RemoveAt (Me.Count - 1)
End If
End Sub
Klasse beenden
Um zu veranschaulichen, wie dieser Klassencode verwendet wird, können Sie ein Formular erstellen, das ihn aufruft. Sie müssten den unten gezeigten Code im Formular verwenden:
Öffentliche Klasse Form1 erbt System.Windows.Forms.Form #Region "Vom Windows Form Designer generierter Code". Außerdem müssen Sie die folgende Anweisung hinzufügen: 'MyControlArray = New LabelArray (Me)' nach dem Aufruf von InitializeComponent () im Code 'hidden Region. 'Deklariere ein neues ButtonArray Objekt. Dim MyControlArray As LabelArray Private Sub btnLabelAdd_Click (_ ByVal Absender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnLabelAdd.Click 'Call the AddNewLabel Methode' von MyControlArray. MyControlArray.AddNewLabel () 'Ändern der BackColor-Eigenschaft' der Schaltfläche 0. MyControlArray (0) .BackColor = _ System.Drawing.Color.Red End Sub Private Sub btnLabelRemove_Click (_ ByVal sender As System.Object, _ ByVal e As System .EventArgs) _ Behandelt btnLabelRemove.Click 'Ruft die Remove-Methode von MyControlArray auf. MyControlArray.Remove () End Sub End Class
Erstens erledigt dies nicht einmal die Arbeit zur Entwurfszeit, wie wir es früher in VB 6 getan haben! Und zweitens befinden sie sich nicht in einem Array, sondern in einer VB.NET-Sammlung - eine ganz andere Sache als ein Array.
Der Grund, warum VB.NET das VB 6 "Control Array" nicht unterstützt, ist, dass es kein "Control" "Array" gibt (beachten Sie die Änderung der Anführungszeichen). Mit VB 6 wird eine Sammlung hinter den Kulissen erstellt und dem Entwickler als Array angezeigt. Aber es ist kein Array und Sie haben nur wenig Kontrolle über die Funktionen, die durch die IDE bereitgestellt werden.
VB.NET hingegen nennt es so, wie es ist: eine Sammlung von Objekten. Und sie übergeben dem Entwickler die Schlüssel zum Königreich, indem sie das Ganze direkt im Freien erstellen.
Als Beispiel für die Art der Vorteile, die dies dem Entwickler bringt, mussten die Steuerelemente in VB 6 vom gleichen Typ sein und denselben Namen haben. Da es sich in VB.NET nur um Objekte handelt, können Sie unterschiedliche Typen festlegen, ihnen unterschiedliche Namen geben und sie dennoch in derselben Objektsammlung verwalten.
In diesem Beispiel behandelt dasselbe Click-Ereignis zwei Schaltflächen und ein Kontrollkästchen und zeigt an, auf welche Schaltfläche geklickt wurde. Tun Sie das in einer Codezeile mit VB 6!
Private Sub MixedControls_Click (_
ByVal Absender Als System.Object, _
ByVal e As System.EventArgs) _
Behandelt Button1.Click, _
Button2.Click, _
CheckBox1.Click
'Die folgende Aussage muss eine lange Aussage sein!
'Es ist in vier Zeilen hier, um es eng zu halten
'genug, um auf eine Webseite zu passen
Label2.Text =
Microsoft.VisualBasic.Right (sender.GetType.ToString,
Len (sender.GetType.ToString) -
(InStr (sender.GetType.ToString, "Forms") + 5))
End Sub
Die Teilstringberechnung ist etwas komplex, aber es ist nicht wirklich das, worüber wir hier sprechen. Sie können im Click-Ereignis alles Mögliche tun. Sie können beispielsweise den Typ des Steuerelements in einer If-Anweisung verwenden, um verschiedene Aktionen für verschiedene Steuerelemente auszuführen.
Franks Arbeitsgruppe lieferte ein Beispiel mit einem Formular, das 4 Beschriftungen und 2 Schaltflächen enthält. Taste 1 löscht die Beschriftungen und Taste 2 füllt sie. Es ist eine gute Idee, Franks ursprüngliche Frage noch einmal zu lesen und zu bemerken, dass das von ihm verwendete Beispiel eine Schleife war, mit der die Caption-Eigenschaft eines Arrays von Label-Komponenten gelöscht wird. Hier ist das VB.NET-Äquivalent zu diesem VB 6-Code. Dieser Code macht das, wonach Frank ursprünglich gefragt hatte!
Öffentliche Klasse Form1 übernimmt System.Windows.Forms.Form #Region "Vom Windows Form Designer generierter Code" Dim LabelArray (4) As Label 'deklariert ein Array von Beschriftungen Private Sub Form1_Load (_ ByVal Absender As System.Object, _ ByVal e As System .EventArgs) _ Behandelt MyBase.Load SetControlArray () End Sub Sub SetControlArray () LabelArray (1) = Label1 LabelArray (2) = Label2 LabelArray (3) = Label3 LabelArray (4) = Label4 End Sub Private Sub Button1_Click (_ ByVal sender Als System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click 'Button 1 Clear Array Dim eine As Integer For a = 1 bis 4 LabelArray (a) .Text = "" Next End Sub Private Sub Button2_Click (_ ByVal Absender Als System.Object, _ ByVal e Als System.EventArgs) _ Behandelt Button2.Click 'Button 2 Array ausfüllen Dim a As Integer Für a = 1 bis 4 LabelArray (a) .Text = _ "Control Array" & CStr ( a) Next End Sub End Class
Wenn Sie mit diesem Code experimentieren, werden Sie feststellen, dass Sie nicht nur die Eigenschaften der Beschriftungen festlegen, sondern auch Methoden aufrufen können. Warum habe ich (und Microsoft) mich dann alle Mühe gegeben, den Code "Ugly" in Teil I des Artikels zu erstellen??
Ich muss nicht zustimmen, dass es sich wirklich um ein "Control Array" im klassischen VB-Sinne handelt. Das VB 6 Control Array ist ein unterstützter Teil der VB 6-Syntax und nicht nur eine Technik. Tatsächlich kann dieses Beispiel möglicherweise so beschrieben werden, dass es sich um ein Array von Steuerelementen und nicht um ein Control Array handelt.
In Teil I habe ich mich darüber beschwert, dass das Microsoft-Beispiel NUR zur Laufzeit und nicht zur Entwurfszeit funktioniert hat. Sie können Steuerelemente dynamisch zu einem Formular hinzufügen und daraus entfernen, das Ganze muss jedoch in Code implementiert werden. Sie können Steuerelemente nicht wie in VB 6 per Drag & Drop erstellen. Dieses Beispiel funktioniert hauptsächlich zur Entwurfszeit und nicht zur Laufzeit. Sie können Steuerelemente zur Laufzeit nicht dynamisch hinzufügen und löschen. In gewisser Weise ist es das genaue Gegenteil des Beispiels von Teil I.
Das klassische Beispiel für ein VB 6-Steuerfeld ist dasselbe, das im VB .NET-Code implementiert ist. Hier in VB 6 Code (dieser stammt von Mezick & Hillier, Visual Basic 6-Zertifizierungsprüfungshandbuch, p 206 - leicht modifiziert, da das Beispiel im Buch zu nicht sichtbaren Steuerelementen führt):
MyTextBox als VB.TextBox dimmen Statisch intNumber als Integer intNumber = intNumber + 1 MyTextBox = _ Me.Controls.Add ("VB.TextBox", _ "Text" & intNumber) MyTextBox.Text = MyTextBox.Name MyTextBox.Visible = True MyTextBox.Left = _ (intNumber - 1) * 1200
Aber wie Microsoft (und ich) zustimmen, sind in VB.NET keine VB 6-Steuerungsarrays möglich. Das Beste, was Sie tun können, ist, die Funktionalität zu duplizieren. Mein Artikel hat die Funktionalität des Mezick & Hillier-Beispiels dupliziert. Der Study Group-Code dupliziert die Funktionalität, Eigenschaften und Aufrufmethoden festlegen zu können.
Unterm Strich kommt es also wirklich darauf an, was Sie tun wollen. VB.NET hat nicht alles als Teil der Sprache verpackt - aber letztendlich ist es weitaus flexibler.
John schrieb: Ich brauchte Steuerfelder, weil ich zur Laufzeit eine einfache Tabelle mit Zahlen in ein Formular einfügen wollte. Ich wollte nicht die Übelkeit haben, sie alle einzeln zu platzieren, und ich wollte VB.NET verwenden. Microsoft bietet eine sehr detaillierte Lösung für ein einfaches Problem, aber es ist ein sehr großer Vorschlaghammer, um eine sehr kleine Nuss zu knacken. Nach einigem Experimentieren bin ich schließlich auf eine Lösung gestoßen. So habe ich es gemacht.
Das obige Beispiel zu Visual Basic zeigt, wie Sie ein Textfeld in einem Formular erstellen können, indem Sie eine Instanz des Objekts erstellen, Eigenschaften festlegen und es der Controls-Auflistung hinzufügen, die Teil des Formularobjekts ist.
Dim txtDataShow As New TextBox
txtDataShow.Height = 19
txtDataShow.Width = 80
txtDataShow.Location = Neuer Punkt (X, Y)
Me.Controls.Add (txtDataShow)
Obwohl die Microsoft-Lösung eine Klasse erstellt, bin ich zu dem Schluss gekommen, dass dies alles stattdessen in eine Unterroutine eingeschlossen werden kann. Jedes Mal, wenn Sie diese Unterroutine aufrufen, erstellen Sie eine neue Instanz des Textfelds im Formular. Hier ist der vollständige Code:
Öffentliche Klasse Form1
Übernimmt System.Windows.Forms.Form
#Region "Vom Windows Form Designer generierter Code"
Private Sub BtnStart_Click (_
ByVal Absender Als System.Object, _
ByVal e As System.EventArgs) _
Verarbeitet btnStart.Click
Dim I As Integer
Dim sData As String
Für I = 1 bis 5
sData = CStr (I)
AddDataShow aufrufen (sData, I)
Nächster
End Sub
Unter AddDataShow (_
ByVal sText As String, _
ByVal I As Integer)
Dim txtDataShow As New TextBox
Dim UserLft, UserTop As Integer
Dim X, Y As Integer
UserLft = 20
UserTop = 20
txtDataShow.Height = 19
txtDataShow.Width = 25
txtDataShow.TextAlign = _
HorizontalAlignment.Center
txtDataShow.BorderStyle = _
BorderStyle.FixedSingle
txtDataShow.Text = sText
X = UserLft
Y = UserTop + (I - 1) * txtDataShow.Height
txtDataShow.Location = Neuer Punkt (X, Y)
Me.Controls.Add (txtDataShow)
End Sub
Klasse beenden
Sehr guter Punkt, John. Dies ist sicherlich viel einfacher als der Microsoft-Code. Deshalb frage ich mich, warum sie darauf bestanden, es so zu machen?
Versuchen Sie zunächst, eine der Eigenschaftszuweisungen im Code zu ändern. Lass uns ändern
txtDataShow.Height = 19
zu
txtDataShow.Height = 100
Nur um sicherzustellen, dass es einen spürbaren Unterschied gibt.
Wenn wir den Code erneut ausführen, erhalten wir ... Was? ... das Gleiche. Überhaupt keine Veränderung. Tatsächlich können Sie den Wert mit einer Anweisung wie MsgBox (txtDataShow.Height) anzeigen, und Sie erhalten immer noch 20 als Wert der Eigenschaft, unabhängig davon, was Sie dieser zuweisen. Warum passiert das??
Die Antwort ist, dass wir nicht unsere eigene Klasse ableiten, um die Objekte zu erstellen, sondern nur Dinge zu einer anderen Klasse hinzufügen, sodass wir den Regeln der anderen Klasse folgen müssen. Und diese Regeln besagen, dass Sie die Height-Eigenschaft nicht ändern können. (Nun ja, das können Sie. Wenn Sie die Multiline-Eigenschaft auf True setzen, können Sie die Höhe ändern.)
Warum VB.NET fortfährt und den Code ausführt, ohne auch nur zu wimmern, dass irgendetwas nicht stimmt, obwohl Ihre Aussage völlig missachtet wird, ist ein weiterer Kritikpunkt. Ich könnte jedoch zumindest eine Warnung in der Kompilierung vorschlagen. (Hinweis! Hinweis! Hinweis! Hört Microsoft zu?)
Das Beispiel aus Teil I erbt von einer anderen Klasse. Dadurch werden die Eigenschaften für den Code in der erbenden Klasse verfügbar. Wenn Sie in diesem Beispiel die Height-Eigenschaft auf 100 ändern, erhalten Sie die erwarteten Ergebnisse. (Nochmals ... ein Haftungsausschluss: Wenn eine neue Instanz einer großen Label-Komponente erstellt wird, wird die alte verdeckt. Um die neuen Label-Komponenten tatsächlich anzuzeigen, müssen Sie die Methode aLabel.BringToFront () hinzufügen.)
Dieses einfache Beispiel zeigt, dass, obwohl wir Objekte einfach einer anderen Klasse hinzufügen KÖNNEN (und manchmal ist dies das Richtige), die Programmiersteuerung über die Objekte erfordert, dass wir sie in einer Klasse und auf die am besten organisierte Weise ableiten (wage ich zu sagen, "Der .NET-Weg" ??) ist es, Eigenschaften und Methoden in der neu abgeleiteten Klasse zu erstellen, um Dinge zu ändern. John blieb zunächst nicht überzeugt. Er sagte, dass sein neuer Ansatz seinem Zweck gerecht werde, obwohl es Einschränkungen gebe, nicht "COO" (Correctly Object Oriented) zu sein. In jüngerer Zeit schrieb John jedoch,
"... nachdem ich zur Laufzeit einen Satz von 5 Textfeldern geschrieben hatte, wollte ich die Daten in einem späteren Teil des Programms aktualisieren - aber nichts hat sich geändert - die ursprünglichen Daten waren noch da.
Ich stellte fest, dass ich das Problem umgehen konnte, indem ich Code schrieb, um die alten Kisten abzunehmen und sie wieder mit neuen Daten zu versehen. Besser wäre es, Me.Refresh zu verwenden. Dieses Problem hat mich jedoch auf die Notwendigkeit aufmerksam gemacht, eine Methode zum Subtrahieren und Hinzufügen der Textfelder bereitzustellen. "
Johns Code verwendete eine globale Variable, um zu verfolgen, wie viele Steuerelemente dem Formular hinzugefügt wurden, sodass eine Methode ...
Private Sub Form1_Load (_
ByVal Absender Als System.Object, _
ByVal e As System.EventArgs) _
Verarbeitet MyBase.Load
CntlCnt0 = Me.Controls.Count
End Sub
Dann könnte das "letzte" Steuerelement entfernt werden ...
N = Me.Controls.Count - 1
Me.Controls.RemoveAt (N)
John bemerkte: "Vielleicht ist das ein bisschen ungeschickt."
Auf diese Weise verfolgt Microsoft Objekte in COM AND in ihrem obigen "hässlichen" Beispielcode.
Ich bin jetzt auf das Problem des dynamischen Erstellens von Steuerelementen in einem Formular zur Laufzeit zurückgekehrt und habe mich erneut mit den Artikeln "Was ist mit Steuerelementen passiert?" Befasst.
Ich habe die Klassen erstellt und kann nun die Steuerelemente wie gewünscht auf dem Formular platzieren.
John demonstrierte, wie die Platzierung von Steuerelementen in einem Gruppenfeld mithilfe der neuen Klassen gesteuert werden kann, mit denen er begonnen hat. Vielleicht hatte Microsoft ja doch Recht mit ihrer "hässlichen" Lösung!