VB.NET: Kaj se je zgodilo s kontrolnimi nizi

Kako ravnati z zbirkami kontrolnikov v VB.NET

Izpustitev kontrolnih nizov iz VB.NET je izziv za tiste, ki poučujejo o nizih.





  • Kontrolnika, kot je besedilno polje, ni več mogoče preprosto kopirati in ga nato prilepiti (enkrat ali večkrat), da ustvarite niz kontrolnikov.
  • Koda VB.NET za ustvarjanje strukture, podobne kontrolni matriki, je bila v vseh knjigah o VB.NET, ki sem jih kupil in na spletu, veliko daljša in veliko bolj zapletena. Nima preprostosti kodiranja kontrolnih nizov, ki jih najdemo v VB6.

Če se sklicujete na združljivo knjižnico VB6, so tam predmeti, ki delujejo precej podobno kontrolnim poljem. Če želite videti, kaj mislim, preprosto uporabite čarovnika za nadgradnjo VB.NET s programom, ki vsebuje kontrolni niz. Koda je spet grda, vendar deluje. Slaba novica je, da Microsoft ne bo zagotovil, da bodo združljivostne komponente še naprej podprte, in jih ne bi smeli uporabljati.

Koda VB.NET za ustvarjanje in uporabo 'kontrolnih nizov' je veliko daljša in veliko bolj zapletena.



Po Microsoftovih besedah ​​je treba narediti nekaj, kar je blizu tistemu, kar lahko storite v VB 6, ustvariti 'preprosto komponento, ki podvaja funkcionalnost kontrolnih nizov.'

Za ponazoritev tega potrebujete nov razred in obrazec za gostovanje. Razred dejansko ustvarja in uničuje nove oznake. Celotna koda razreda je naslednja:



Javni razred LabelArray
Podeduje System.Collections.CollectionBase
Zasebni gostiteljski obrazec samo za branje kot _
System.Windows.Forms.Form
Javna funkcija AddNewLabel() _
Kot System.Windows.Forms.Label
' Ustvarite nov primerek razreda Label.
Zatemni aLabel kot novo System.Windows.Forms.Label
' Dodajte oznako v zbirko
' notranji seznam.
Me.List.Add(aLabel)
' Dodajte oznako v zbirko kontrolnikov
' obrazca, na katerega se sklicuje polje HostForm.
HostForm.Controls.Add(aLabel)
' Nastavite začetne lastnosti za objekt Label.
aLabel.Top = Število * 25
aLabel.Width = 50
aLabel.Left = 140
aLabel.Tag = Me.Count
aLabel.Text = 'Oznaka ' & Me.Count.ToString
Vrni oznako
Končna funkcija
Javni Sub Novo ( _
ByVal gostitelj kot System.Windows.Forms.Form)
HostForm = gostitelj
Me.AddNewLabel()
End Sub
Privzeta javna lastnost samo za branje _
Postavka (indeks ByVal kot celo število) kot _
System.Windows.Forms.Label
Dobiti
Vrni CType(Me.List.Item(Index), _
System.Windows.Forms.Label)
Konec Get
Končna lastnina
Odstrani javni pod()
' Preverite, ali obstaja oznaka za odstranitev.
Če Me.Count > 0 Potem
' Odstranite zadnjo oznako, dodano v matriko
' iz zbirke kontrolnikov gostiteljskega obrazca.
' Upoštevajte uporabo privzete lastnosti v
' dostop do matrike.
HostForm.Controls.Remove(Me(Me.Count - 1))
Me.List.RemoveAt(Me.Count - 1)
Konec Če
End Sub
Končaj razred

Za ponazoritev uporabe te kode razreda lahko ustvarite obrazec, ki jo kliče. Uporabiti bi morali kodo, prikazano spodaj v obrazcu:

|_+_|

Prvič, to sploh ne opravlja dela v Design Timeu, kot smo to počeli v VB 6! In drugič, niso v matriki, so v zbirki VB.NET - precej drugačna stvar kot matrika.

Razlog, da VB.NET ne podpira 'kontrolne matrike' VB 6, je, da ne obstaja 'kontrolna' 'matrika' (upoštevajte spremembo narekovajev). VB 6 ustvari zbirko v zakulisju in jo razvijalcu prikaže kot niz. Vendar to ni polje in nad njim imate malo nadzora, razen funkcij, ki jih zagotavlja IDE.



Po drugi strani pa VB.NET to imenuje kar je: zbirka predmetov. In predajo ključe kraljestva razvijalcu tako, da ustvarijo celotno stvar kar na prostem.

Kot primer vrste prednosti, ki jih to daje razvijalcu, so morali v VB 6 kontrolniki biti iste vrste in imeti so morali isto ime. Ker so to samo predmeti v VB.NET, jih lahko spremenite v različne tipe in jim daste različna imena ter jih še vedno upravljate v isti zbirki predmetov.



V tem primeru isti dogodek Click obravnava dva gumba in potrditveno polje ter prikaže, kateri je bil kliknjen. Naredite to v eni vrstici kode z VB 6!

Private Sub MixedControls_Click( _
ByVal pošiljatelj kot System.Object, _
ByVal e As System.EventArgs) _
Ročaji Button1.Click, _
Button2.Click, _
Potrditveno polje1. Kliknite
' Spodnja izjava mora biti ena dolga izjava!
' Tukaj je v štirih vrsticah, da ostane ozko
' dovolj, da se prilega spletni strani
Oznaka2.Besedilo =
Microsoft.VisualBasic.Right(sender.GetType.ToString,
Len(sender.GetType.ToString) -
(InStr(sender.GetType.ToString, 'Forms') + 5))
End Sub



Izračun podniza je nekoliko zapleten, vendar tukaj pravzaprav ne govorimo o tem. V dogodku Click lahko počnete karkoli. Uporabite lahko na primer vrsto kontrolnika v stavku If, da naredite različne stvari za različne kontrolnike.

Povratne informacije Frankove skupine za računalniške študije o nizih

Frankova študijska skupina je ponudila primer z obrazcem, ki ima 4 oznake in 2 gumba. Gumb 1 počisti oznake, gumb 2 pa jih zapolni. Dobro je, da še enkrat preberete Frankovo ​​izvirno vprašanje in opazite, da je bil primer, ki ga je uporabil, zanka, ki se uporablja za brisanje lastnosti Caption niza komponent Label. Tukaj je VB.NET ekvivalent te kode VB 6. Ta koda naredi tisto, kar je Frank prvotno zahteval!



|_+_|

Če eksperimentirate s to kodo, boste ugotovili, da lahko poleg nastavljanja lastnosti oznak kličete tudi metode. Zakaj sem se torej jaz (in Microsoft) potrudil, da sem zgradil 'grdo' kodo v I. delu članka?

Ne strinjam se, da je v resnici 'Control Array' v klasičnem smislu VB. VB 6 Control Array je podprt del sintakse VB 6, ne le tehnika. Pravzaprav bi ta primer morda lahko opisali tako, da gre za niz kontrolnikov, ne kontrolni niz.

V I. delu sem se pritožil, da je Microsoftov primer deloval SAMO v času izvajanja in ne v času načrtovanja. Kontrolnike lahko dodajate in brišete iz obrazca dinamično, vendar mora biti vsa stvar implementirana v kodo. Ne morete povleči in spustiti kontrolnikov, da bi jih ustvarili, kot lahko v VB 6. Ta primer deluje predvsem v času načrtovanja in ne v času izvajanja. Kontrolnikov ne morete dinamično dodajati in brisati med izvajanjem. Na nek način je popolno nasprotje primera iz I. dela.

Klasični primer nadzorne matrike VB 6 je enak tistemu, ki je implementiran v kodo VB .NET. Tukaj v kodi VB 6 (to je vzeto od Mezick & Hillier, Vodnik za certifikacijski izpit Visual Basic 6 , str 206 - rahlo spremenjeno, saj primer v knjigi povzroči kontrole, ki jih ni mogoče videti):

|_+_|

Toda kot se Microsoft (in jaz) strinjava, kontrolni nizi VB 6 v VB.NET niso mogoči. Najboljše, kar lahko naredite, je torej, da podvojite funkcionalnost. Moj članek je podvajal funkcionalnost, ki jo najdemo v primeru Mezick & Hillier. Koda študijske skupine podvoji funkcionalnost, ki omogoča nastavitev lastnosti in klicnih metod.

Bistvo je torej, da je res odvisno od tega, kaj želite početi. VB.NET nima vsega zavitega kot del jezika -- vendar -- vendar je navsezadnje veliko bolj prilagodljiv.

John Fannon Take on Control Arrays

John je napisal: Potreboval sem kontrolna polja, ker sem želel postaviti preprosto tabelo s številkami na obrazec med izvajanjem. Nisem želel slabega postavljanja vseh posamično in želel sem uporabiti VB.NET. Microsoft ponuja zelo podrobno rešitev za preprost problem, vendar je zelo veliko kladivo, da streš zelo majhen oreh. Po nekaj eksperimentiranju sem končno naletel na rešitev. Evo, kako sem to naredil.

Zgornji primer O Visual Basicu prikazuje, kako lahko ustvarite TextBox na obrazcu tako, da ustvarite primerek predmeta, nastavite lastnosti in ga dodate v zbirko Controls, ki je del predmeta Form.

Zatemni txtDataShow kot novo besedilno polje
txtDataShow.Height = 19
txtDataShow.Width = 80
txtDataShow.Location = Nova točka(X, Y)
Me.Controls.Add(txtDataShow)
Čeprav Microsoftova rešitev ustvari razred, sem sklepal, da bi bilo mogoče vse to namesto tega zaviti v podprogram. Vsakič, ko pokličete ta podprogram, ustvarite nov primerek besedilnega polja na obrazcu. Tukaj je celotna koda:

Obrazec javnega razreda1
Podeduje System.Windows.Forms.Form

#Region ' Windows Form Designer generirana koda '

Zasebni Sub BtnStart_Click( _
ByVal pošiljatelj kot System.Object, _
ByVal e As System.EventArgs) _
Obravnava btnStart.Click

Dim I kot celo število
Dim sData kot niz
Za jaz = 1 do 5
sPodatki = CStr(I)
Pokliči AddDataShow(sData, I)
Naslednji
End Sub
Sub AddDataShow( _
ByVal sText kot niz, _
ByVal I kot celo število)

Zatemni txtDataShow kot novo besedilno polje
Dim UserLft, UserTop kot celo število
Dim X, Y kot celo število
UserLft = 20
Uporabniški vrh = 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 = Nova točka(X, Y)
Me.Controls.Add(txtDataShow)
End Sub
Končaj razred
Zelo dobro, John. To je zagotovo veliko preprostejše od Microsoftove kode ... zato se sprašujem, zakaj so vztrajali pri tem?

Za začetek preiskave poskusimo spremeniti eno od dodelitev lastnosti v kodi. Spremenimo se

txtDataShow.Height = 19
do

txtDataShow.Height = 100
samo zato, da se prepričam, da je opazna razlika.

Ko znova zaženemo kodo, dobimo ... Whaaaat??? ... ista stvar. Brez sprememb. Pravzaprav lahko prikažete vrednost z izjavo, kot je MsgBox (txtDataShow.Height), in še vedno dobite 20 kot vrednost lastnosti, ne glede na to, kaj ji dodelite. Zakaj se to zgodi?

Odgovor je, da ne izpeljemo lastnega razreda za ustvarjanje predmetov, samo dodajamo stvari drugemu razredu, tako da moramo upoštevati pravila drugega razreda. In ta pravila določajo, da ne morete spremeniti lastnosti Height. (No ... lahko. Če spremenite lastnost Multiline na True, potem lahko spremenite višino.)

Zakaj VB.NET nadaljuje in izvaja kodo, ne da bi se celo zamislil, da bi lahko bilo kaj narobe, medtem ko v resnici popolnoma ne upošteva vaše izjave, je čisto nič. Lahko pa predlagam vsaj opozorilo v prevajanju. (Namig! Namig! Namig! Ali Microsoft posluša?)

Primer iz I. dela podeduje od drugega razreda, zaradi česar so lastnosti na voljo kodi v podedujočem razredu. Če v tem primeru spremenimo lastnost Height na 100, dobimo pričakovane rezultate. (Spet ... ena zavrnitev odgovornosti: Ko je ustvarjen nov primerek velike komponente Label, prekrije starega. Če želite dejansko videti nove komponente Label, morate dodati klic metode aLabel.BringToFront().)

Ta preprost primer kaže, da čeprav LAHKO preprosto dodamo predmete v drug razred (in včasih je to prava stvar), programski nadzor nad objekti zahteva, da jih izpeljemo v razredu in na najbolj organiziran način (upam si reči, 'način .NET'??) je ustvariti lastnosti in metode v novem izpeljanem razredu za spreminjanje stvari. Janez sprva ni bil prepričan. Rekel je, da njegov novi pristop ustreza njegovemu namenu, čeprav obstajajo omejitve, ker ni 'COO' (pravilno usmerjen v objekt). Pred kratkim pa je John zapisal,

' ... po tem, ko sem med izvajanjem napisal nabor 5 besedilnih polj, sem želel posodobiti podatke v naslednjem delu programa - vendar se ni nič spremenilo - prvotni podatki so bili še vedno tam.

Ugotovil sem, da lahko težavo rešim tako, da napišem kodo, da odstranim stare škatle in jih znova postavim nazaj z novimi podatki. Boljši način za to bi bila uporaba Me.Refresh. Toda ta težava je pritegnila mojo pozornost zaradi potrebe po zagotovitvi metode za odštevanje besedilnih polj in njihovo dodajanje.'

Johnova koda je uporabila globalno spremenljivko za sledenje temu, koliko kontrolnikov je bilo dodanih v obrazec, tako da je metoda ...

Zasebni podobrazec1_Nalaganje( _
ByVal pošiljatelj kot System.Object, _
ByVal e As System.EventArgs) _
Obravnava MyBase.Load
CntlCnt0 = Me.Controls.Count
End Sub

Potem bi lahko 'zadnji' nadzor odstranili ...

N = Me.Controls.Count - 1
Me.Controls.RemoveAt(N)
John je opozoril, da je 'morda to nekoliko nerodno.'

To je način, na katerega Microsoft sledi objektom v COM IN v njihovi 'grdi' vzorčni kodi zgoraj.

Zdaj sem se vrnil k problemu dinamičnega ustvarjanja kontrolnikov na obrazcu med izvajanjem in ponovno sem si ogledal članke »Kaj se je zgodilo s kontrolnimi nizi«.

Ustvaril sem razrede in zdaj lahko postavim kontrolnike na obrazec tako, kot želim.

John je pokazal, kako nadzorovati postavitev kontrolnikov v skupinskem polju z uporabo novih razredov, ki jih je začel uporabljati. Mogoče je Microsoft vendarle imel prav v svoji 'grdi' rešitvi!