VB.NET Wat is er gebeurd om arrays te besturen?

Het weglaten van controlarrays uit VB.NET is een uitdaging voor diegenen die lesgeven in arrays.

  • Het is niet langer mogelijk om een ​​besturingselement, zoals een tekstvak, te kopiëren en vervolgens (een of meerdere keren) te plakken om een ​​besturingsmatrix te maken.
  • De VB.NET-code voor het maken van een structuur die lijkt op een controlematrix is ​​in alle boeken op VB.NET die ik en online heb gekocht, veel langer en veel complexer. Het ontbreekt aan de eenvoud van het coderen van een besturingsmatrix die in VB6 wordt gevonden.

Als u verwijst naar de VB6-compatibiliteitsbibliotheek, bevinden zich daar objecten die ongeveer als regelarrays werken. Om te zien wat ik bedoel, gebruikt u eenvoudig de VB.NET-upgradewizard met een programma dat een controlarray bevat. De code is weer lelijk, maar het werkt. Het slechte nieuws is dat Microsoft niet kan garanderen dat de compatibiliteitscomponenten worden ondersteund en dat u deze niet mag gebruiken.

De VB.NET-code voor het maken en gebruiken van "controlarrays" is veel langer en veel complexer.

Volgens Microsoft is het nodig om iets te doen dat zelfs in de buurt komt van wat u in VB 6 kunt doen, een "eenvoudige component die de functionaliteit van de besturingsarray dupliceert".

U hebt zowel een nieuwe klasse als een hostingformulier nodig om dit te illustreren. De klasse creëert en vernietigt eigenlijk nieuwe labels. De volledige klassencode is als volgt:

Public Class LabelArray
    Overleeft System.Collections.CollectionBase
    Privé alleen-lezen Hostformulier als _
    System.Windows.Forms.Form
    Openbare functie AddNewLabel () _
    Als System.Windows.Forms.Label
        'Maak een nieuwe instantie van de klasse Label.
        Dim aLabel As New System.Windows.Forms.Label
        'Voeg het label toe aan de collecties
    interne lijst.
        Me.List.Add (Alabel)
        'Voeg het label toe aan de collectie Besturing   
        'van het formulier waarnaar wordt verwezen door het veld HostForm.
        HostForm.Controls.Add (Alabel)
        'Stel initiële eigenschappen in voor het Label-object.
        aLabel.Top = Aantal * 25
        aLabel.Width = 50
        aLabel.Left = 140
        aLabel.Tag = Me.Count
        aLabel.Text = "Label" & Me.Count.ToString
        Retourneer aLabel
    Einde functie
    Public Sub Nieuw (_
    ByVal-host als System.Windows.Forms.Form)
        HostForm = host
        Me.AddNewLabel ()
    Einde Sub
    Standaard openbare alleen-lezen eigenschap _
        Artikel (ByVal-index als geheel getal) als _
        System.Windows.Forms.Label
        Krijgen
            Retour CType (Me.List.Item (Index), _
        System.Windows.Forms.Label)
        Einde ophalen
    Einde eigendom
    Public Sub Verwijderen ()
        'Controleer of er een label is om te verwijderen.
        Als Me.Count> 0 dan
            'Verwijder het laatste label dat aan de array is toegevoegd 
            'uit de verzameling hostbesturingselementen. 
        'Let op het gebruik van de standaardeigenschap in 
            toegang tot de array.
            HostForm.Controls.Remove (Me (Me.Count - 1))
            Me.List.RemoveAt (Me.Count - 1)
        Stop als
    Einde Sub
Eindklasse

Om te illustreren hoe deze klassecode zou worden gebruikt, kunt u een formulier maken dat het aanroept. U zou de onderstaande code in het formulier moeten gebruiken:

Public Class Form1 Inherits System.Windows.Forms.Form #Region "Windows Form Designer gegenereerde code" 'Ook moet u de instructie:' MyControlArray = New LabelArray (Me) 'toevoegen na de aanroep InitializeComponent () in de' verborgen regiocode '. 'Verklaar een nieuw ButtonArray-object. Dim MyControlArray As LabelArray Private Sub btnLabelAdd_Click (_ ByVal-afzender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnLabelAdd.Click 'Bel de AddNewLabel-methode' van MyControlArray. MyControlArray.AddNewLabel () 'De eigenschap BackColor wijzigen' van knop 0. MyControlArray (0) .BackColor = _ System.Drawing.Color.Red End Sub Private Sub btnLabelRemove_Click (_ ByVal-afzender als System.Object, _ ByVal e als systeem .EventArgs) _ Handles btnLabelRemove.Click 'Roep de verwijdermethode van MyControlArray op. MyControlArray.Remove () End Sub End Class

Ten eerste doet dit niet eens het werk tijdens Design Time zoals we dat vroeger in VB 6 deden! En ten tweede, ze zijn niet in een array, ze zijn in een VB.NET-collectie - iets heel anders dan een array.

De reden dat VB.NET de "control array" van VB 6 niet ondersteunt, is dat er niet zoiets bestaat als een "control" array (let op de wijziging van de aanhalingstekens). VB 6 maakt een verzameling achter de schermen en laat deze als een array voor de ontwikkelaar verschijnen. Maar het is geen array en u hebt er weinig controle over, behalve de functies die door de IDE worden geboden.

VB.NET noemt het daarentegen wat het is: een verzameling objecten. En ze overhandigen de sleutels van het koninkrijk aan de ontwikkelaar door het hele ding recht in de openbaarheid te creëren.

Als een voorbeeld van het soort voordelen dat dit de ontwikkelaar oplevert, moesten de bedieningselementen in VB 6 van hetzelfde type zijn en dezelfde naam hebben. Aangezien dit slechts objecten in VB.NET zijn, kunt u ze verschillende typen maken en ze verschillende namen geven en ze toch in dezelfde verzameling objecten beheren.

In dit voorbeeld verwerkt dezelfde Click-gebeurtenis twee knoppen en een selectievakje en wordt weergegeven op welke knop is geklikt. Doe dat op één regel code met VB 6!

Private Sub MixedControls_Click (_
    ByVal-afzender als System.Object, _
    ByVal e As System.EventArgs) _
    Handles Button1.Click, _
            Button2.Click, _
            CheckBox1.Click
    'De onderstaande verklaring moet een lange verklaring zijn!
    'Het is hier op vier regels om het nauw te houden
    genoeg om op een webpagina te passen
    Label2.Text = 
    Microsoft.VisualBasic.Right (sender.GetType.ToString, 
    Len (sender.GetType.ToString) - 
    (InStr (afzender.GetType.ToString, "Forms") + 5))
Einde Sub

De berekening van de substring is nogal ingewikkeld, maar het is niet echt waar we het hier over hebben. Je zou alles kunnen doen in de Click-gebeurtenis. U kunt bijvoorbeeld het Type van het besturingselement in een If-instructie gebruiken om verschillende dingen voor verschillende besturingselementen te doen.

Frank's Computing Studies Group Feedback op arrays

Frank's studiegroep gaf een voorbeeld met een formulier met 4 labels en 2 knoppen. Knop 1 wist de labels en knop 2 vult ze. Het is een goed idee om de oorspronkelijke vraag van Frank opnieuw te lezen en op te merken dat het voorbeeld dat hij gebruikte een lus was die wordt gebruikt om de titel van een reeks Label-componenten te wissen. Hier is het VB.NET-equivalent van die VB 6-code. Deze code doet waar Frank oorspronkelijk om vroeg!

Public Class Form1 Inherits System.Windows.Forms.Form #Region "Windows Form Designer gegenereerde code" Dim LabelArray (4) As Label 'declareren een reeks labels Private Sub Form1_Load (_ ByVal afzender als System.Object, _ ByVal e As System .EventArgs) _ Handles 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) As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click 'Button 1 Clear Array Dim a As Integer voor a = 1 tot 4 LabelArray (a) .Text = "" Next End Sub Private Sub Button2_Click (_ ByVal-afzender als System.Object, _ ByVal e als System.EventArgs) _ Handles Button2.Click 'Button 2 Fill Array Dim a As Integer voor a = 1 tot 4 LabelArray (a) .Text = _ "Control Array" & CStr ( a) Volgende einde subeindklasse

Als u met deze code experimenteert, zult u ontdekken dat u naast het instellen van eigenschappen van de labels ook methoden kunt aanroepen. Dus waarom heb ik (en Microsoft) al het mogelijke gedaan om de "Lelijke" code in Deel I van het artikel te bouwen?

Ik ben het er niet mee eens dat het echt een "Control Array" is in de klassieke VB-zin. De VB 6 Control Array is een ondersteund onderdeel van de VB 6-syntaxis, niet alleen een techniek. Misschien is de manier om dit voorbeeld te beschrijven misschien dat het een reeks besturingselementen is, geen besturingsmatrix.

In deel I heb ik geklaagd dat het Microsoft-voorbeeld ALLEEN tijdens de uitvoering werkte en niet tijdens het ontwerpen. U kunt op dynamische wijze besturingselementen uit een formulier toevoegen en verwijderen, maar het geheel moet in code worden geïmplementeerd. U kunt besturingselementen niet slepen en neerzetten om ze te maken zoals in VB 6. Dit voorbeeld werkt voornamelijk tijdens het ontwerp en niet tijdens de uitvoering. U kunt besturingselementen niet tijdens runtime dynamisch toevoegen en verwijderen. In zekere zin is dit het tegenovergestelde van het voorbeeld van deel I..

Het klassieke VB 6-besturingsarrayvoorbeeld is hetzelfde als dat is geïmplementeerd in de VB .NET-code. Hier in VB 6-code (deze is afkomstig van Mezick & Hillier, Visual Basic 6 certificering examenhandleiding, p 206 - enigszins aangepast, omdat het voorbeeld in het boek resulteert in bedieningselementen die niet zichtbaar zijn):

Dim MyTextBox als VB.TextBox Statisch intNumber als Integer intNumber = intNumber + 1 Set MyTextBox = _ Me.Controls.Add ("VB.TextBox", _ "Text" & intNumber) MyTextBox.Text = MyTextBox.Name MyTextBox.Visible = True MyTextBox.Left = _ (intNumber - 1) * 1200

Maar zoals Microsoft (en ik) het eens zijn, zijn VB 6-besturingsarrays niet mogelijk in VB.NET. U kunt dus het beste de functionaliteit dupliceren. Mijn artikel dupliceerde de functionaliteit in het voorbeeld van Mezick & Hillier. De Study Group-code dupliceert de functionaliteit van het kunnen instellen van eigenschappen en aanroepmethoden.

Dus het komt erop neer dat het echt afhangt van wat je wilt doen. VB.NET heeft nog niet alles ingepakt als onderdeel van de taal - maar toch - maar uiteindelijk is het veel flexibeler.

John Fannon's Take on Control Arrays

John schreef: ik had controle-arrays nodig omdat ik tijdens de uitvoering een eenvoudige tabel met getallen op een formulier wilde zetten. Ik wilde niet de misselijkheid om ze allemaal afzonderlijk te plaatsen en ik wilde VB.NET gebruiken. Microsoft biedt een zeer gedetailleerde oplossing voor een eenvoudig probleem, maar het is een zeer grote voorhamer om een ​​zeer kleine noot te kraken. Na wat experimenteren kwam ik uiteindelijk op een oplossing. Hier is hoe ik het deed.

Het bovenstaande voorbeeld van Visual Basic laat zien hoe u een TextBox op een formulier kunt maken door een instantie van het object te maken, eigenschappen in te stellen en deze toe te voegen aan de collectie Besturingselementen die deel uitmaakt van het formulierobject.

Dim txtDataShow As New TextBox
txtDataShow.Height = 19
txtDataShow.Width = 80
txtDataShow.Location = Nieuw punt (X, Y)
Me.Controls.Add (txtDataShow)
Hoewel de Microsoft-oplossing een klasse creëert, dacht ik dat het mogelijk zou zijn dit allemaal in een subroutine te verpakken. Telkens wanneer u deze subroutine aanroept, maakt u een nieuwe instantie van het tekstvak op het formulier. Hier is de complete code:

Formulier openbare klasse 1
    Overleeft System.Windows.Forms.Form

#Region "Door Windows Form Designer gegenereerde code"

    Private Sub BtnStart_Click (_
        ByVal-afzender als System.Object, _
        ByVal e As System.EventArgs) _
        Handgrepen btnStart.Click

        Dim I als geheel getal
        Dim sData As String
        Voor I = 1 tot 5
            sData = CStr (I)
            Bel AddDataShow (sData, I)
        De volgende
    Einde Sub
    Sub AddDataShow (_
        ByVal sText As String, _
        ByVal I As Integer)

        Dim txtDataShow As New TextBox
        Dim UserLft, UserTop As Integer
        Dim X, Y als geheel getal
        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 = Nieuw punt (X, Y)
        Me.Controls.Add (txtDataShow)
    Einde Sub
Eindklasse
Zeer goed punt, John. Dit is zeker een stuk eenvoudiger dan de Microsoft-code ... dus ik vraag me af waarom ze erop stonden het zo te doen?

Laten we om te beginnen met het onderzoek een van de eigenschapstoewijzingen in de code wijzigen. Laten we veranderen

txtDataShow.Height = 19
naar

txtDataShow.Height = 100
gewoon om er zeker van te zijn dat er een merkbaar verschil is.

Als we de code opnieuw uitvoeren, krijgen we ... Whaaaat ??? ... hetzelfde. Geen enkele verandering. U kunt de waarde zelfs weergeven met een instructie als MsgBox (txtDataShow.Height) en u krijgt nog steeds 20 als de waarde van de eigenschap, ongeacht wat u eraan toewijst. Waarom gebeurt dat??

Het antwoord is dat we niet onze eigen klasse afleiden om de objecten te maken, we voegen alleen dingen toe aan een andere klasse, dus we moeten de regels van de andere klasse volgen. En in die regels staat dat u de eigenschap Height niet kunt wijzigen. (Wellllll ... dat kan. Als u de eigenschap Multiline in True wijzigt, kunt u de hoogte wijzigen.)

Waarom VB.NET doorgaat en de code uitvoert zonder zelfs maar een gejammer dat er iets mis is terwijl het in feite uw verklaring volledig negeert, is een hele klacht. Ik zou echter ten minste een waarschuwing in de compilatie kunnen voorstellen. (Hint! Hint! Hint! Luistert Microsoft?)

Het voorbeeld uit deel I neemt over van een andere klasse en hierdoor zijn de eigenschappen beschikbaar voor de code in de overnemende klasse. Als u de eigenschap Height in dit voorbeeld wijzigt in 100, krijgt u de verwachte resultaten. (Nogmaals ... één disclaimer: wanneer een nieuw exemplaar van een groot Label-onderdeel wordt gemaakt, bedekt het het oude. Om de nieuwe Label-onderdelen daadwerkelijk te zien, moet u de methode call aLabel.BringToFront () toevoegen.)

Dit eenvoudige voorbeeld laat zien dat, hoewel we eenvoudigweg objecten aan een andere klasse kunnen toevoegen (en soms is dit het juiste om te doen), het programmeren van de controle over de objecten vereist dat we ze op een klasse en op de meest georganiseerde manier afleiden (durf ik te zeggen, "de .NET-manier" ??) is het creëren van eigenschappen en methoden in de nieuwe afgeleide klasse om dingen te veranderen. John bleef aanvankelijk niet overtuigd. Hij zei dat zijn nieuwe aanpak bij zijn doel past, ook al zijn er beperkingen om niet "COO" te zijn (correct objectgeoriënteerd). Meer recent schreef John echter,

"... na het schrijven van een set van 5 tekstvakken tijdens runtime, wilde ik de gegevens in een volgend deel van het programma bijwerken - maar er veranderde niets - de originele gegevens waren er nog.

Ik ontdekte dat ik het probleem kon omzeilen door code te schrijven om de oude dozen te verwijderen en weer terug te zetten met nieuwe gegevens. Een betere manier om dit te doen is door Me.Refresh te gebruiken. Maar dit probleem heeft mijn aandacht getrokken voor de noodzaak om een ​​methode te leveren om de tekstvakken af ​​te trekken en ze toe te voegen. "

John's code gebruikte een globale variabele om bij te houden hoeveel besturingselementen aan het formulier waren toegevoegd, dus een methode ...

Private Sub Form1_Load (_
   ByVal-afzender als System.Object, _
   ByVal e As System.EventArgs) _
   Handgrepen MyBase.Load
   CntlCnt0 = Me.Controls.Count
Einde Sub

Dan kon de "laatste" controle worden verwijderd ...

N = Me.Controls.Count - 1
Me.Controls.RemoveAt (N)
John merkte op dat "dit misschien een beetje onhandig is."

Het is de manier waarop Microsoft objecten bijhoudt in COM EN in hun "lelijke" voorbeeldcode hierboven.

Ik ben nu teruggekomen op het probleem van het dynamisch maken van besturingselementen op een formulier tijdens runtime en ik heb de artikelen 'Wat is er gebeurd met controle-arrays' opnieuw bekeken.

Ik heb de klassen gemaakt en kan nu de besturingselementen op het formulier plaatsen zoals ik wil.

John demonstreerde hoe hij de plaatsing van besturingselementen in een groepsvak kon besturen met behulp van de nieuwe klassen die hij is gaan gebruiken. Misschien had Microsoft het toch goed in hun "lelijke" oplossing!