VB.NET: Vad hände med att kontrollera matriser

Utelämnandet av kontrollmatriser från VB.NET är en utmaning för dem som undervisar om matriser.

  • Det är inte längre möjligt att helt enkelt kopiera en kontroll, till exempel en textruta, och sedan klistra in den (en eller flera gånger) för att skapa en kontrollgrupp.
  • VB.NET-koden för att skapa en struktur som liknar en kontrollgrupp har, i alla böcker på VB.NET som jag har köpt och online, varit mycket längre och mycket mer komplex. Det saknar enkelheten i att koda en kontrollgrupp som finns i VB6.

Om du hänvisar till VB6-kompatibilitetsbiblioteket finns det objekt där som fungerar ganska mycket som kontrollmatriser. För att se vad jag menar, använd bara VB.NET-uppgraderingsguiden med ett program som innehåller en kontrollgrupp. Koden är ful igen, men den fungerar. De dåliga nyheterna är att Microsoft inte kommer att garantera att kompatibilitetskomponenterna kommer att fortsätta att stödjas, och du ska inte använda dem.

VB.NET-koden för att skapa och använda "kontrollmatriser" är mycket längre och mycket mer komplex.

instagram viewer

Enligt Microsoft kräver skapandet en "enkel komponent som duplicerar kontrollfunktionens funktionalitet" för att göra något till och med vad du kan göra i VB 6.

Du behöver både en ny klass och ett värdformulär för att illustrera detta. Klassen skapar och förstör faktiskt nya etiketter. Den fullständiga klasskoden är som följer:

Public Class LabelArray
Arvssystem. Samlingar. CollectionBase
Privat ReadOnly HostForm As _
Systemet. Windows. Former. Form
Public Function AddNewLabel () _
Som system. Windows. Former. Märka
"Skapa en ny instans av Label-klassen.
Dim aLabel som nytt system. Windows. Former. Märka
Lägg till etiketten i samlingen
"intern lista.
Mig. Lista. Lägg till (aLabel)
Lägg till etiketten i kontroller-samlingen
'i formuläret som refereras av fältet HostForm.
HostForm. Kontroller. Lägg till (aLabel)
'Ställ in intima egenskaper för Label-objektet.
en etikett. Top = Count * 25
en etikett. Bredd = 50
en etikett. Vänster = 140
en etikett. Tagg = mig. Räkna
en etikett. Text = "Etikett" & Mig. Räkna. Att stränga
Retur aLabel
Avsluta funktion
Public Sub New (_
ByVal värd som system. Windows. Former. Form)
HostForm = värd
Mig. AddNewLabel ()
Avsluta under
Standard Public ReadOnly Property _
Objekt (ByVal Index som heltal) Som _
Systemet. Windows. Former. Märka
Skaffa sig
Returnera CType (Me. List. Artikel (index), _
Systemet. Windows. Former. Märka)
Slut Get
Slut egendom
Public Sub Ta bort ()
"Kontrollera att det finns en etikett att ta bort.
Om jag. Räkna> 0 Sedan
'Ta bort den sista etiketten som lagts till i matrisen
"från värdformuläret kontrollerar samlingen.
'Notera användningen av standardegenskapen i
"åtkomst till matrisen.
HostForm. Kontroller. Ta bort (jag (jag. Räkning - 1))
Mig. Lista. RemoveAt (Me. Count - 1)
Sluta om
Avsluta under
Slutklass

För att illustrera hur denna klasskod skulle användas kan du skapa ett formulär som kallar det. Du måste använda koden som visas nedan i formuläret:

Public Class Form1. Arvssystem. Windows. Former. Form. #Region "Windows Form Designer genererad kod" 'Du måste också lägga till uttalandet:' MyControlArray = New LabelArray (Me) efter att InitializeComponent () anropar. "dold regionskod. "Förklara ett nytt ButtonArray-objekt. Dim MyControlArray som LabelArray. Privat sub btnLabelAdd_Click (_. ByVal avsändare som system. Objekt, _. ByVal e As System. EventArgs) _. Hanterar btnLabelAdd. Klick. "Ring AddNewLabel-metoden. av MyControlArray. MyControlArray. AddNewLabel () 'Ändra egenskapen BackColor. av knappen 0. MyControlArray (0) .BackColor = _. Systemet. Teckning. Färg. Röd. Avsluta under. Privat sub btnLabelRemove_Click (_. ByVal avsändare som system. Objekt, _. ByVal e As System. EventArgs) _. Hanterar btnLabelRemove. Klick. "Ring metoden Ta bort från MyControlArray. MyControlArray. Ta bort() Avsluta under. Slutklass

Först gör detta inte ens jobbet på Design Time som vi brukade göra det i VB 6! Och för det andra är de inte i en matris, de finns i en VB.NET-samling - en mycket annorlunda sak än en matris.

Anledningen till att VB.NET inte stöder VB 6 "kontrollarray" är att det inte finns något sådant som ett "kontroll" "array" (notera ändringen av citattecken). VB 6 skapar en samling bakom kulisserna och får den att visas som en matris för utvecklaren. Men det är inte ett array och du har liten kontroll över det utöver de funktioner som tillhandahålls genom IDE.

VB.NET, å andra sidan, kallar det vad det är: en samling av objekt. Och de överlämnar nycklarna till kungariket till utvecklaren genom att skapa hela saken helt utomhus.

Som ett exempel på vilken typ av fördelar detta ger utvecklaren, i VB 6 måste kontrollerna vara av samma typ, och de måste ha samma namn. Eftersom detta bara är objekt i VB.NET kan du göra dem till olika typer och ge dem olika namn och ändå hantera dem i samma samling av objekt.

I det här exemplet hanterar samma Click-händelse två knappar och en kryssruta och visar vilken som klickades på. Gör det i en kodrad med VB 6!

Privat sub MixedControls_Click (_
ByVal avsändare som system. Objekt, _
ByVal e As System. EventArgs) _
Handtag-knapp1.Klicka, _
Knapp2.Klicka, _
CheckBox1.Click
”Uttalandet nedan måste vara ett långt uttalande!
"Det är på fyra rader här för att hålla det smalt
tillräckligt för att passa på en webbsida
Label2.Text =
Microsoft. Visual Basic. Höger (avsändare. GetType. Att stränga,
Len (avsändare. GetType. Att stränga) -
(InStr (avsändare. GetType. ToString, "Forms") + 5))
Avsluta under

Substringsberäkningen är typ av komplex, men det är inte riktigt vad vi pratar om här. Du kan göra vad som helst i Click-evenemanget. Du kan till exempel använda typ av kontroll i ett If-uttalande för att göra olika saker för olika kontroller.

Frank's Group Computing Studies Group Feedback om Arrays

Frank's Study Group gav ett exempel med ett formulär som har fyra etiketter och 2 knappar. Knapp 1 rensar etiketterna och knapp 2 fyller dem. Det är en bra idé att läsa Franks ursprungliga fråga igen och lägga märke till att exemplet han använde var en slinga som används för att rensa bildtextsegenskapen för en rad etikettkomponenter. Här är VB.NET-motsvarigheten till den VB 6-koden. Den här koden gör vad Frank ursprungligen bad om!

Public Class Form1. Arvssystem. Windows. Former. Form. #Region "Windows Form Designer genererad kod" Dim LabelArray (4) Som etikett. "förklara en mängd etiketter. Privat subform1_Load (_. ByVal avsändare som system. Objekt, _. ByVal e As System. EventArgs) _. Hanterar MyBase. Ladda. SetControlArray () Avsluta under. Sub SetControlArray () LabelArray (1) = Etikett1. LabelArray (2) = Label2. LabelArray (3) = Label3. LabelArray (4) = Label4. Avsluta under. Privat subknapp1_Klicka (_. ByVal avsändare som system. Objekt, _. ByVal e As System. EventArgs) _. Handtag-knapp1.Klicka. 'Knapp 1 Rensa array. Dim ett som heltal. För a = 1 till 4. LabelArray (a) .Text = "" Nästa. Avsluta under. Privat subknapp2_Klicka (_. ByVal avsändare som system. Objekt, _. ByVal e As System. EventArgs) _. Handtag-knapp2.Klicka. 'Knapp 2 Fyll Array. Dim ett som heltal. För a = 1 till 4. LabelArray (a). Text = _. "Control Array" & CStr (a) Nästa. Avsluta under. Slutklass

Om du experimenterar med den här koden kommer du att upptäcka att du förutom att ställa in egenskaper för etiketter också kan ringa metoder. Så varför gjorde jag (och Microsoft) alla problem med att bygga den "fula" koden i del I av artikeln?

Jag måste hålla med om att det verkligen är ett "Control Array" i klassisk mening. VB 6 Control Array är en stödd del av VB 6-syntaxen, inte bara en teknik. Faktum är att kanske sättet att beskriva detta exempel är att det är en mängd kontroller, inte en kontrollgrupp.

I del I klagade jag över att Microsoft-exemplet KUN fungerade vid körtid och inte designtid. Du kan lägga till och ta bort kontroller från ett formulär dynamiskt, men det hela måste implementeras i kod. Du kan inte dra och släppa kontrollerna för att skapa dem som du kan i VB 6. Detta exempel fungerar huvudsakligen vid designtid och inte vid körtid. Du kan inte lägga till och ta bort kontroller dynamiskt vid körning. På ett sätt är det hela motsatsen till del I-exemplet.

Det klassiska VB 6-kontrollarrayexemplet är detsamma som implementeras i VB .NET-koden. Här i VB 6-kod (detta är hämtat från Mezick & Hillier, Visual Basic 6 Certification Exam Guide, s 206 - något modifierat, eftersom exemplet i boken resulterar i kontroller som inte kan ses):

Dim MyTextBox som VB.TextBox. Statisk intNummer som heltal. intNumber = intNumber + 1. Ställ in MyTextBox = _. Mig. Kontroller. Lägg till ("VB.TextBox", _. "Text" & intNummer) MyTextBox. Text = MyTextBox. Namn. MyTextBox. Synlig = sant. MyTextBox. Vänster = _. (intNummer - 1) * 1200

Men som Microsoft (och jag) håller med, är VB 6-kontrollmatriser inte möjliga i VB.NET. Så det bästa du kan göra är att kopiera funktionaliteten. Min artikel duplicerade funktionaliteten som finns i Mezick & Hillier-exemplet. Studiegruppskoden duplicerar funktionaliteten för att kunna ställa in egenskaper och samtalsmetoder.

Så slutet är att det verkligen beror på vad du vill göra. VB.NET har inte hela saken lindad som en del av språket - Ändå - men i slutändan är det mycket mer flexibelt.

John Fannons Take on Control Arrays

John skrev: Jag behövde kontrollmatriser eftersom jag ville lägga en enkel tabell över siffror på ett formulär vid körning. Jag ville inte ha illamående att placera dem alla individuellt och jag ville använda VB.NET. Microsoft erbjuder en mycket detaljerad lösning på ett enkelt problem, men det är en väldigt stor slägga som knäcker en mycket liten mutter. Efter lite experiment försökte jag så småningom en lösning. Så här gjorde jag det.

Exemplet About Visual Basic ovan visar hur du kan skapa en TextBox på ett formulär genom att skapa en instans av objektet, ställa in egenskaper och lägga till det i kontrollsamlingen som är en del av formuläret objekt.

Dim txtData Visa som ny textbox
txtDataShow. Höjd = 19
txtDataShow. Bredd = 80
txtDataShow. Plats = Ny punkt (X, Y)
Mig. Kontroller. Lägg till (txtDataShow)
Även om Microsoft-lösningen skapar en klass, resonerade jag att det i stället skulle vara möjligt att förpacka allt detta i en subrutin. Varje gång du ringer till denna subrutin skapar du en ny instans av textrutan i formuläret. Här är den fullständiga koden:

Public Class Form1
Arvssystem. Windows. Former. Form

#Region "Windows Form Designer genererad kod"

Privat sub BtnStart_Click (_
ByVal avsändare som system. Objekt, _
ByVal e As System. EventArgs) _
Hanterar btnStart. Klick

Dim I som heltal
Dim sData som sträng
För I = 1 till 5
sData = CStr (I)
Ring AddDataShow (sData, I)
Nästa
Avsluta under
Sub AddDataShow (_
ByVal sText As String, _
ByVal jag som heltal)

Dim txtData Visa som ny textbox
Dim UserLft, UserTop som heltal
Dim X, Y Som heltal
UserLft = 20
UserTop = 20
txtDataShow. Höjd = 19
txtDataShow. Bredd = 25
txtDataShow. TextAlign = _
Horisontell linjering. Centrum
txtDataShow. BorderStyle = _
Border. FixedSingle
txtDataShow. Text = sText
X = UserLft
Y = UserTop + (I - 1) * txtDataShow. Höjd
txtDataShow. Plats = Ny punkt (X, Y)
Mig. Kontroller. Lägg till (txtDataShow)
Avsluta under
Slutklass
Mycket bra poäng, John. Detta är verkligen mycket enklare än Microsoft-koden... så jag undrar varför de insisterade på att göra det så?

För att börja vår utredning, låt oss försöka ändra en av fastighetsuppgifterna i koden. Låt oss ändra

txtDataShow. Höjd = 19
till

txtDataShow. Höjd = 100
bara för att se till att det finns en märkbar skillnad.

När vi kör koden igen får vi... Whaaaat??? ... samma sak. Ingen förändring alls. I själva verket kan du visa värdet med ett uttalande som MsgBox (txtDataShow. Höjd) och du får fortfarande 20 som värdet på fastigheten oavsett vad du tilldelar den. Varför händer det?

Svaret är att vi inte härleder vår egen klass för att skapa föremål, vi lägger bara till saker i en annan klass så vi måste följa reglerna för den andra klassen. Och dessa regler säger att du inte kan ändra egenskapen Höjd. (Wellllll... du kan. Om du ändrar egenskapen Multiline till True kan du ändra höjden.)

Varför VB.NET går vidare och kör koden utan att ens en gnista att det kan vara något fel när det i själva verket helt bortser från ditt uttalande är en hel "nother gripe". Jag kan dock föreslå åtminstone en varning i kompilering, dock. (Ledtråd! Ledtråd! Ledtråd! Lyssnar Microsoft?)

Exemplet från del I ärver från en annan klass, och detta gör egenskaperna tillgängliga för koden i arvklassen. Att ändra egenskapen Höjd till 100 i detta exempel ger oss de förväntade resultaten. (Igen... en ansvarsfriskrivning: När en ny instans av en stor etikettkomponent skapas täcker den den gamla. För att faktiskt se de nya etikettkomponenterna måste du lägga till metodsamtalet aLabel. BringToFront ().)

Detta enkla exempel visar att även om vi KAN helt enkelt lägga till objekt i en annan klass (och ibland är det rätt att göra), programmerar du kontroll över objekten kräver att vi härleder dem i en klass och det mest organiserade sättet (vågar jag säga, ".NET-sättet" ??) är att skapa egenskaper och metoder i den nya härledda klassen för att ändra saker. John förblev övertygad till en början. Han sa att hans nya tillvägagångssätt passar hans syfte även om det finns begränsningar från att inte vara "COO" (korrekt objektorienterad). Men nyligen skrev John,

"... Efter att ha skrivit en uppsättning med 5 textlådor under körning, ville jag uppdatera data i en efterföljande del av programmet - men ingenting förändrades - de ursprungliga uppgifterna var fortfarande kvar.

Jag fann att jag kunde komma runt problemet genom att skriva kod för att ta bort de gamla rutorna och sätta tillbaka dem igen med ny data. Ett bättre sätt att göra det vore att använda mig. Uppdatera. Men detta problem har fått min uppmärksamhet för behovet av att tillhandahålla en metod för att subtrahera textrutorna och lägga till dem. "

Johns kod använde en global variabel för att hålla reda på hur många kontroller som hade lagts till i formuläret så en metod ...

Privat subform1_Load (_
ByVal avsändare som system. Objekt, _
ByVal e As System. EventArgs) _
Hanterar MyBase. Ladda
CntlCnt0 = Jag. Kontroller. Räkna
Avsluta under

Sedan kan den "sista" kontrollen tas bort ...

N = Mig. Kontroller. Räkna - 1
Mig. Kontroller. Ta bort (N)
John noterade att "kanske detta är lite klumpigt."

Det är så Microsoft håller reda på objekt i KOM OCH i deras "fula" exempelkod ovan.

Jag har nu återvänt till problemet med att dynamiskt skapa kontroller på ett formulär vid körningstid och jag har tittat igen på artiklarna "What Happened to Control Arrays".

Jag har skapat klasserna och kan nu placera kontrollerna på formen på det sätt jag vill att de ska vara.

John demonstrerade hur man kontrollerar placeringen av kontroller i en gruppruta med de nya klasserna han har börjat använda. Kanske hade Microsoft rätt i sin "fula" lösning trots allt!

instagram story viewer