L'omissione delle matrici di controllo da VB.NET è una sfida per coloro che insegnano le matrici.
- Non è più possibile semplicemente copiare un controllo, ad esempio una casella di testo, e quindi incollarlo (una o più volte) per creare un array di controllo.
- Il codice VB.NET per la creazione di una struttura simile a un array di controllo è stato, in tutti i libri su VB.NET che ho acquistato e online, molto più lungo e molto più complesso. Manca la semplicità di codificare un array di controllo che si trova in VB6.
Se si fa riferimento alla libreria di compatibilità VB6, ci sono oggetti che agiscono in modo simile alle matrici di controllo. Per capire cosa intendo, è sufficiente utilizzare la procedura guidata di aggiornamento di VB.NET con un programma che contiene un array di controllo. Il codice è di nuovo brutto, ma funziona. La cattiva notizia è che Microsoft non garantirà che i componenti di compatibilità continueranno a essere supportati e non dovresti usarli.
Il codice VB.NET per creare e utilizzare "array di controllo" è molto più lungo e molto più complesso.
Secondo Microsoft, per fare qualcosa di simile a quello che si può fare in VB 6 è necessario creare un "semplice componente che duplica la funzionalità di array di controllo".
È necessario sia una nuova classe che un modulo di hosting per illustrare questo. La classe in realtà crea e distrugge nuove etichette. Il codice completo della classe è il seguente:
Classe pubblica LabelArray
Eredita il sistema. Collezioni. CollectionBase
Private ReadOnly HostForm As _
Sistema. Finestre. Le forme. Modulo
Funzione pubblica AddNewLabel () _
Come sistema. Finestre. Le forme. Etichetta
'Crea una nuova istanza della classe Label.
Dim etichetta come nuovo sistema. Finestre. Le forme. Etichetta
'Aggiungi l'etichetta alla collezione
'elenco interno.
Me. Elenco. Aggiungi (aLabel)
'Aggiungi l'etichetta alla raccolta dei controlli
"del modulo a cui fa riferimento il campo HostForm.
HostForm. Controlli. Aggiungi (aLabel)
'Imposta le proprietà iniziali per l'oggetto Label.
un'etichetta. Superiore = Conteggio * 25
un'etichetta. Larghezza = 50
un'etichetta. Sinistra = 140
un'etichetta. Tag = Me. Contare
un'etichetta. Text = "Etichetta" & Me. Contare. Accordare
Restituisci etichetta
Fine funzione
Public Sub Nuovo (_
Host ByVal come sistema. Finestre. Le forme. Modulo)
HostForm = host
Me. AddNewLabel ()
End Sub
Proprietà ReadOnly pubblica predefinita _
Articolo (indice ByVal come intero) come _
Sistema. Finestre. Le forme. Etichetta
Ottenere
Return CType (Elenco Me. Articolo (indice), _
Sistema. Finestre. Le forme. Etichetta)
End Get
Proprietà finale
Public Sub Remove ()
'Verificare che sia presente un'etichetta da rimuovere.
Se io. Conteggio> 0 Quindi
'Rimuovi l'ultima etichetta aggiunta all'array
"dalla raccolta dei controlli del modulo host.
'Nota l'uso della proprietà predefinita in
'accesso all'array.
HostForm. Controlli. Rimuovi (Me (Me. Count - 1))
Me. Elenco. RemoveAt (Me. Count - 1)
Finisci se
End Sub
End Class
Per illustrare come verrà utilizzato questo codice di classe, è possibile creare un modulo che lo chiama. Dovresti usare il codice mostrato sotto nel modulo:
Modulo di classe pubblica 1. Eredita il sistema. Finestre. Le forme. Modulo. #Region "Codice generato da Progettazione Windows Form" 'Inoltre è necessario aggiungere l'istruzione:' MyControlArray = New LabelArray (Me) 'dopo la chiamata InitializeComponent () in. 'codice regionale nascosto. 'Dichiara un nuovo oggetto ButtonArray. Dim MyControlArray As LabelArray. Sottotitoli privati btnLabelAdd_Click (_. Mittente ByVal come sistema. Oggetto, _. ByVal e As System. EventArgs) _. Maniglie btnLabelAdd. Clic. 'Chiama il metodo AddNewLabel. "di MyControlArray. MyControlArray. AddNewLabel () 'Modifica la proprietà BackColor. "del pulsante 0. MyControlArray (0) .BackColor = _. Sistema. Disegno. Colore. Rosso. End Sub. Sottotitoli privati btnLabelRemove_Click (_. Mittente ByVal come sistema. Oggetto, _. ByVal e As System. EventArgs) _. Gestisce btnLabelRemove. Clic. 'Chiama il metodo Remove di MyControlArray. MyControlArray. Rimuovere() End Sub. End Class
In primo luogo, questo non fa nemmeno il lavoro in Design Time come facevamo in VB 6! E in secondo luogo, non sono in un array, sono in una raccolta VB.NET - una cosa molto diversa da un array.
La ragione per cui VB.NET non supporta la "matrice di controllo" VB 6 è che non esiste una "matrice" di "controllo" (notare la modifica delle virgolette). VB 6 crea una raccolta dietro le quinte e la fa apparire come un array allo sviluppatore. Ma non è un array e hai poco controllo su di esso oltre le funzioni fornite tramite l'IDE.
VB.NET, d'altra parte, lo chiama così com'è: una raccolta di oggetti. E consegnano le chiavi del regno allo sviluppatore creando l'intera cosa all'aperto.
Come esempio del tipo di vantaggi che ciò offre allo sviluppatore, in VB 6 i controlli dovevano essere dello stesso tipo e dovevano avere lo stesso nome. Dato che questi sono solo oggetti in VB.NET, puoi renderli di tipi diversi e dare loro nomi diversi e gestirli comunque nella stessa raccolta di oggetti.
In questo esempio, lo stesso evento Click gestisce due pulsanti e una casella di controllo e visualizza quello su cui è stato fatto clic. Fallo in una riga di codice con VB 6!
Sottotitoli privati MixedControls_Click (_
Mittente ByVal come sistema. Oggetto, _
ByVal e As System. EventArgs) _
Pulsante Maniglie1. Fare clic su, _
Button2.Click, _
CheckBox1.Click
'La seguente dichiarazione deve essere una lunga affermazione!
'È su quattro righe qui per mantenerlo stretto
'abbastanza per adattarsi a una pagina web
Label2.Text =
Microsoft. Visual Basic. Giusto (mittente. GetType. Accordare,
Len (mittente. GetType. Accordare) -
(InStr (mittente. GetType. ToString, "Forms") + 5))
End Sub
Il calcolo della sottostringa è piuttosto complesso, ma non è proprio quello di cui stiamo parlando qui. Puoi fare qualsiasi cosa nell'evento Click. Ad esempio, è possibile utilizzare il Tipo di controllo in un'istruzione If per eseguire operazioni diverse per controlli diversi.
Feedback del gruppo di studi di calcolo di Frank sugli array
Il gruppo di studio di Frank ha fornito un esempio con un modulo con 4 etichette e 2 pulsanti. Il pulsante 1 cancella le etichette e il pulsante 2 le riempie. È una buona idea leggere nuovamente la domanda originale di Frank e notare che l'esempio che ha usato era un ciclo che viene utilizzato per cancellare la proprietà Caption di una matrice di componenti Label. Ecco l'equivalente VB.NET di quel codice VB 6. Questo codice fa quello che Frank aveva inizialmente richiesto!
Modulo di classe pubblica 1. Eredita il sistema. Finestre. Le forme. Modulo. #Region "Codice generato da Progettazione Windows Form" Dim LabelArray (4) Come etichetta. 'dichiarare una matrice di etichette. Sottomodulo privato1_Load (_. Mittente ByVal come sistema. Oggetto, _. ByVal e As System. EventArgs) _. Gestisce MyBase. Caricare. SetControlArray () End Sub. Sub SetControlArray () LabelArray (1) = Label1. LabelArray (2) = Label2. LabelArray (3) = Label3. LabelArray (4) = Label4. End Sub. Pulsante secondario privato1_Fare clic su (_. Mittente ByVal come sistema. Oggetto, _. ByVal e As System. EventArgs) _. Pulsante Maniglie1. Fare clic su. 'Pulsante 1 Cancella array. Dim a As Intero. Per a = 1 a 4. LabelArray (a) .Text = "" Il prossimo. End Sub. Private Sub Button2_Click (_. Mittente ByVal come sistema. Oggetto, _. ByVal e As System. EventArgs) _. Maniglie Button2.Click. 'Pulsante 2 Riempi matrice. Dim a As Intero. Per a = 1 a 4. LabelArray (a) .Text = _. "Control Array" e CStr (a) Il prossimo. End Sub. End Class
Se si sperimenta questo codice, scoprirai che oltre a impostare le proprietà delle etichette, puoi anche chiamare metodi. Allora perché io (e Microsoft) ho fatto tutto il possibile per creare il codice "Brutto" nella parte I dell'articolo?
Non sono d'accordo sul fatto che sia davvero un "Control Array" nel senso classico del VB. L'array di controllo VB 6 è una parte supportata della sintassi VB 6, non solo una tecnica. In effetti, forse il modo per descrivere questo esempio è che si tratta di una matrice di controlli, non di una matrice di controllo.
Nella parte I, mi sono lamentato del fatto che l'esempio di Microsoft funzionava SOLO in fase di esecuzione e non in fase di progettazione. È possibile aggiungere ed eliminare i controlli da un modulo in modo dinamico, ma tutto deve essere implementato nel codice. Non puoi trascinare i controlli per crearli come puoi in VB 6. Questo esempio funziona principalmente in fase di progettazione e non in fase di esecuzione. Non è possibile aggiungere ed eliminare i controlli in modo dinamico in fase di esecuzione. In un certo senso, è l'esatto contrario dell'esempio della Parte I.
Il classico esempio dell'array di controllo VB 6 è lo stesso implementato nel codice VB .NET. Qui nel codice VB 6 (questo è preso da Mezick & Hillier, Guida agli esami di certificazione Visual Basic 6, p 206 - leggermente modificato, poiché l'esempio nel libro risulta in controlli che non possono essere visti):
Dim MyTextBox come VB.TextBox. IntNumber statico come intero. intNumber = intNumber + 1. Imposta MyTextBox = _. Me. Controlli. Aggiungi ("VB.TextBox", _. "Testo" e intNumber) MyTextBox. Testo = MyTextBox. Nome. MyTextBox. Visibile = Vero. MyTextBox. Sinistra = _. (intNumber - 1) * 1200
Ma, come concordano Microsoft (e I), in VB.NET non sono possibili array di controllo VB 6. Quindi il meglio che puoi fare è duplicare la funzionalità. Il mio articolo ha duplicato la funzionalità trovata nell'esempio di Mezick & Hillier. Il codice del gruppo di studio duplica la funzionalità di poter impostare proprietà e metodi di chiamata.
Quindi la linea di fondo è che dipende davvero da cosa vuoi fare. VB.NET non ha tutto racchiuso come parte del linguaggio - Eppure - ma alla fine è molto più flessibile.
Take on Control Arrays di John Fannon
John ha scritto: Avevo bisogno di array di controllo perché volevo mettere una semplice tabella di numeri in un modulo in fase di esecuzione. Non volevo la nausea nel metterli tutti singolarmente e volevo usare VB.NET. Microsoft offre una soluzione molto dettagliata a un semplice problema, ma è una mazza molto grande per rompere un dado molto piccolo. Dopo un po 'di sperimentazione, alla fine ho trovato una soluzione. Ecco come l'ho fatto.
L'esempio Informazioni su Visual Basic sopra mostra come è possibile creare una casella di testo in un modulo creando un'istanza dell'oggetto, impostando le proprietà e aggiungendolo alla raccolta Controls che fa parte del modulo oggetto.
Dim txtDataShow As New TextBox
txtDataShow. Altezza = 19
txtDataShow. Larghezza = 80
txtDataShow. Posizione = Nuovo punto (X, Y)
Me. Controlli. Aggiungi (txtDataShow)
Sebbene la soluzione Microsoft crei una classe, ho pensato che sarebbe stato possibile racchiudere tutto ciò in una subroutine. Ogni volta che si chiama questa subroutine, si crea una nuova istanza della casella di testo nel modulo. Ecco il codice completo:
Modulo di classe pubblica 1
Eredita il sistema. Finestre. Le forme. Modulo
#Region "Codice generato da Progettazione Windows Form"
Private Sub BtnStart_Click (_
Mittente ByVal come sistema. Oggetto, _
ByVal e As System. EventArgs) _
Maniglie btnStart. Clic
Dim I come intero
Dim sData As String
Per I = 1 a 5
sData = CStr (I)
Chiama AddDataShow (sData, I)
Il prossimo
End Sub
AddDataShow secondario (_
ByVal sText As String, _
ByVal I come numero intero)
Dim txtDataShow As New TextBox
Dim UserLft, UserTop As Intero
Dim X, Y come numero intero
UserLft = 20
UserTop = 20
txtDataShow. Altezza = 19
txtDataShow. Larghezza = 25
txtDataShow. TextAlign = _
Allineamento orizzontale. Centro
txtDataShow. BorderStyle = _
Stile del bordo. FixedSingle
txtDataShow. Text = sText
X = UserLft
Y = UserTop + (I - 1) * txtDataShow. Altezza
txtDataShow. Posizione = Nuovo punto (X, Y)
Me. Controlli. Aggiungi (txtDataShow)
End Sub
End Class
Ottimo punto, John. Questo è sicuramente molto più semplice del codice Microsoft... quindi mi chiedo perché abbiano insistito per farlo in quel modo?
Per iniziare la nostra indagine, proviamo a modificare una delle assegnazioni di proprietà nel codice. Facciamo cambio
txtDataShow. Altezza = 19
per
txtDataShow. Altezza = 100
solo per assicurarsi che ci sia una notevole differenza.
Quando eseguiamo di nuovo il codice, otteniamo... Whaaaat??? ... la stessa cosa. Nessun cambiamento. In effetti, è possibile visualizzare il valore con un'istruzione come MsgBox (txtDataShow. Altezza) e ottieni comunque 20 come valore della proprietà, indipendentemente da ciò che le assegni. Perché succede?
La risposta è che non stiamo derivando la nostra classe per creare gli oggetti, stiamo solo aggiungendo cose a un'altra classe, quindi dobbiamo seguire le regole dell'altra classe. E quelle regole affermano che non è possibile modificare la proprietà Height. (Wellllll... Puoi. Se si modifica la proprietà multilinea su True, è possibile modificare l'altezza.)
Perché VB.NET va avanti ed esegue il codice senza nemmeno un lamento che potrebbe esserci qualcosa di sbagliato quando, in realtà, ignora totalmente la tua affermazione è un tutt'altra lamentela. Potrei suggerire almeno un avvertimento nella compilazione, tuttavia. (Suggerimento! Suggerimento! Suggerimento! Microsoft sta ascoltando?)
L'esempio della Parte I eredita da un'altra Classe e ciò rende le proprietà disponibili per il codice nella Classe ereditante. La modifica della proprietà Height su 100 in questo esempio ci dà i risultati previsti. (Ancora... una dichiarazione di non responsabilità: quando viene creata una nuova istanza di un componente Label di grandi dimensioni, copre quella precedente. Per visualizzare effettivamente i nuovi componenti Label, è necessario aggiungere il metodo call aLabel. Portare in primo piano().)
Questo semplice esempio mostra che, sebbene possiamo semplicemente aggiungere oggetti a un'altra classe (e talvolta questa è la cosa giusta da fare), programmare il controllo sugli oggetti richiede che li deriviamo in una Classe e il modo più organizzato (oserei dire "il modo .NET" ??) è creare proprietà e metodi nella nuova Classe derivata da modificare cose. All'inizio John non rimase convinto. Ha detto che il suo nuovo approccio si adatta al suo scopo anche se ci sono dei limiti a non essere "COO" (orientato correttamente agli oggetti). Più recentemente, tuttavia, John ha scritto,
"... dopo aver scritto un set di 5 caselle di testo in fase di esecuzione, volevo aggiornare i dati in una parte successiva del programma - ma non è cambiato nulla - i dati originali erano ancora lì.
Ho scoperto che avrei potuto aggirare il problema scrivendo il codice per rimuovere le vecchie scatole e rimetterle di nuovo con nuovi dati. Un modo migliore per farlo sarebbe usare Me. Ricaricare. Ma questo problema ha attirato la mia attenzione sulla necessità di fornire un metodo per sottrarre le caselle di testo e aggiungerle ".
Il codice di John utilizzava una variabile globale per tenere traccia di quanti controlli erano stati aggiunti al modulo, quindi un metodo ...
Sottomodulo privato1_Load (_
Mittente ByVal come sistema. Oggetto, _
ByVal e As System. EventArgs) _
Gestisce MyBase. Caricare
CntlCnt0 = Me. Controlli. Contare
End Sub
Quindi il controllo "ultimo" potrebbe essere rimosso ...
N = Me. Controlli. Conteggio - 1
Me. Controlli. RemoveAt (N)
John notò che "forse è un po 'goffo".
È il modo in cui Microsoft tiene traccia degli oggetti in COM E nel loro codice di esempio "brutto" sopra.
Ora sono tornato al problema della creazione dinamica di controlli in un modulo in fase di esecuzione e ho rivisto gli articoli "Cosa è successo al controllo degli array".
Ho creato le classi e ora posso posizionare i controlli sul modulo nel modo in cui voglio che siano.
John ha dimostrato come controllare il posizionamento dei controlli in una casella di gruppo utilizzando le nuove classi che ha iniziato a utilizzare. Forse Microsoft aveva ragione nella sua soluzione "brutta" dopo tutto!