VB.NET: Co się stało z tablicami kontrolnymi?
Jak obsługiwać kolekcje kontrolek w VB.NET?
Pominięcie tablic kontrolnych w VB.NET jest wyzwaniem dla osób uczących się o tablicach.
- Nie można już po prostu skopiować kontrolki, takiej jak pole tekstowe, a następnie wkleić ją (raz lub kilka razy) w celu utworzenia tablicy kontrolnej.
- Kod VB.NET do tworzenia struktury podobnej do tablicy kontrolnej był we wszystkich książkach o VB.NET, które kupiłem i online, o wiele dłuższy i znacznie bardziej złożony. Brakuje w nim prostoty kodowania tablicy kontrolnej, którą można znaleźć w VB6.
Jeśli odwołujesz się do biblioteki kompatybilności VB6, znajdują się tam obiekty, które działają prawie jak tablice kontrolne. Aby zobaczyć, o co mi chodzi, wystarczy skorzystać z kreatora aktualizacji VB.NET z programem, który zawiera tablicę kontrolną. Kod znów jest brzydki, ale działa. Zła wiadomość jest taka, że Microsoft nie gwarantuje, że komponenty kompatybilności będą nadal obsługiwane i nie powinieneś ich używać.
Kod VB.NET do tworzenia i używania „tablic kontrolnych” jest znacznie dłuższy i bardziej złożony.
Według Microsoftu zrobienie czegoś nawet zbliżonego do tego, co można zrobić w VB 6, wymaga stworzenia „prostego komponentu, który powiela funkcjonalność tablicy kontrolnej”.
Aby to zilustrować, potrzebujesz zarówno nowej klasy, jak i formularza hostingowego. Klasa faktycznie tworzy i niszczy nowe etykiety. Pełny kod zajęć wygląda następująco:
Tablica etykiet klasy publicznej
Dziedziczy System.Collections.CollectionBase
Prywatny formularz hosta tylko do odczytu jako _
System.Windows.Forms.Form
Funkcja publiczna AddNewLabel() _
Jako System.Windows.Forms.Label
' Utwórz nową instancję klasy Label.
Dim aLabel jako nowy system.Windows.Forms.Label
' Dodaj etykietę do kolekcji
lista wewnętrzna.
Dodaj(aEtykieta)
' Dodaj etykietę do kolekcji Kontrolki
' formularza, do którego odwołuje się pole HostForm.
HostForm.Controls.Add(aLabel)
' Ustaw początkowe właściwości obiektu Label.
aLabel.Top = Liczba * 25
a Etykieta.Szerokość = 50
aEtykieta.Lewo = 140
aLabel.Tag = Ja.Liczba
aLabel.Text = 'Label ' & Me.Count.ToString
Zwróć etykietę
Koniec funkcji
Publiczny Sub Nowy( _
Host ByVal jako System.Windows.Forms.Form)
HostForm = host
Ja.DodajNowąEtykietę()
Napis końcowy
Domyślna właściwość publiczna tylko do odczytu _
Pozycja (Indeks ByVal jako liczba całkowita) As _
System.Windows.Forms.Label
Dostać
Zwróć CType(Me.List.Item(Index), _
System.Windows.Forms.Label)
Koniec Pobierz
Koniec właściwości
Publiczna Sub Usuń()
' Sprawdź, czy istnieje etykieta do usunięcia.
Jeśli Me.Count > 0 Wtedy
' Usuń ostatnią etykietę dodaną do tablicy
' z kolekcji formantów formularza hosta.
' Zwróć uwagę na użycie domyślnej właściwości w
' dostęp do tablicy.
HostForm.Controls.Remove(Me(Me.Count - 1))
Me.List.RemoveAt(Me.Count - 1)
Zakończ, jeśli
Napis końcowy
Koniec klasy
Aby zilustrować sposób użycia tego kodu klasy, możesz utworzyć formularz, który go wywołuje. Musiałbyś użyć kodu pokazanego poniżej w formularzu:
|_+_|Po pierwsze, to nawet nie działa w czasie projektowania, tak jak robiliśmy to w VB 6! Po drugie, nie znajdują się one w tablicy, są w kolekcji VB.NET - coś zupełnie innego niż tablica.
Powodem, dla którego VB.NET nie obsługuje „tablicy kontrolnej” VB 6 jest to, że nie ma czegoś takiego jak „tablica” „kontroli” (zwróć uwagę na zmianę cudzysłowów). VB 6 tworzy zakulisową kolekcję i sprawia, że jest ona widoczna dla programisty jako tablica. Ale nie jest to tablica i masz nad nią niewielką kontrolę poza funkcjami dostarczanymi przez IDE.
Z drugiej strony VB.NET nazywa go tym, czym jest: kolekcją obiektów. I przekazują klucze do królestwa deweloperowi, tworząc całość od razu na otwartej przestrzeni.
Jako przykład korzyści, jakie daje to programista, w VB 6 kontrolki musiały być tego samego typu i musiały mieć tę samą nazwę. Ponieważ są to tylko obiekty w VB.NET, możesz uczynić je różnymi typami i nadać im różne nazwy i nadal zarządzać nimi w tej samej kolekcji obiektów.
W tym przykładzie to samo zdarzenie Click obsługuje dwa przyciski i pole wyboru oraz wyświetla, który z nich został kliknięty. Zrób to w jednym wierszu kodu z VB 6!
Private Sub MixedControls_Click( _
ByVal nadawca Jako System.Object, _
ByVal e As System.EventArgs) _
Przyciski uchwytów1.Kliknij, _
Przycisk2.Kliknij, _
Pole wyboru1.Kliknij
' Poniższe stwierdzenie musi być jednym długim stwierdzeniem!
'Tu jest na czterech liniach, aby był wąski
' wystarczy, aby zmieścić się na stronie internetowej
Etykieta2.Tekst =
Microsoft.VisualBasic.Right(sender.GetType.ToString,
Len(sender.GetType.ToString) —
(InStr(sender.GetType.ToString, 'Formularze') + 5))
Napis końcowy
Obliczanie podłańcuchów jest dość skomplikowane, ale tak naprawdę to nie jest to, o czym tutaj mówimy. Możesz zrobić wszystko w wydarzeniu Click. Możesz na przykład użyć Type kontrolki w instrukcji If, aby zrobić różne rzeczy dla różnych kontrolek.
Opinie grupy Frank's Computing Studies na temat tablic
Grupa badawcza Franka dostarczyła przykład z formularzem, który ma 4 etykiety i 2 przyciski. Przycisk 1 czyści etykiety, a przycisk 2 je wypełnia. Dobrym pomysłem jest ponowne przeczytanie oryginalnego pytania Franka i zauważenie, że przykładem, którego użył, była pętla używana do czyszczenia właściwości Caption tablicy składników Label. Oto odpowiednik VB.NET tego kodu VB 6. Ten kod robi to, o co początkowo prosił Frank!
|_+_|
Jeśli poeksperymentujesz z tym kodem, odkryjesz, że oprócz ustawiania właściwości etykiet możesz również wywoływać metody. Dlaczego więc ja (i Microsoft) zadałem sobie tyle trudu, aby zbudować „brzydki” kod w części I artykułu?
Muszę się nie zgodzić, że tak naprawdę jest to „tablica kontrolna” w klasycznym sensie VB. Tablica kontrolna VB 6 jest obsługiwaną częścią składni VB 6, a nie tylko techniką. W rzeczywistości, być może sposobem na opisanie tego przykładu jest to, że jest to tablica kontrolek, a nie tablica kontrolna.
W części I narzekałem, że przykład Microsoftu działał TYLKO w czasie wykonywania, a nie w czasie projektowania. Możesz dynamicznie dodawać i usuwać kontrolki z formularza, ale całość musi być zaimplementowana w kodzie. Nie można przeciągać i upuszczać kontrolek, aby je tworzyć, tak jak w VB 6. Ten przykład działa głównie w czasie projektowania, a nie w czasie wykonywania. W czasie wykonywania nie można dynamicznie dodawać ani usuwać kontrolek. W pewnym sensie jest to całkowite przeciwieństwo przykładu z części I.
Klasyczny przykład tablicy kontrolnej VB 6 jest tym samym, który jest zaimplementowany w kodzie VB .NET. Tutaj w kodzie VB 6 (pochodzi z Mezick & Hillier, Przewodnik po egzaminach certyfikacyjnych Visual Basic 6 , s. 206 - nieznacznie zmodyfikowana, ponieważ przykład w książce daje niewidoczne kontrolki):
|_+_|Ale jak Microsoft (i ja) zgadzamy się, tablice kontrolne VB 6 nie są możliwe w VB.NET. Więc najlepsze, co możesz zrobić, to powielić funkcjonalność. Mój artykuł powielał funkcjonalność z przykładu Mezick & Hillier. Kod Study Group powiela funkcjonalność możliwości ustawiania właściwości i wywoływania metod.
Najważniejsze jest to, że to naprawdę zależy od tego, co chcesz zrobić. VB.NET nie zawiera całości jako części języka -- jeszcze -- ale ostatecznie jest znacznie bardziej elastyczny.
Podejmij się kontroli tablic kontrolnych Johna Fannona
John napisał: Potrzebowałem tablic kontrolnych, ponieważ chciałem umieścić prostą tabelę liczb na formularzu w czasie wykonywania. Nie chciałem mdłości umieszczania ich wszystkich pojedynczo i chciałem użyć VB.NET. Microsoft oferuje bardzo szczegółowe rozwiązanie prostego problemu, ale to bardzo duży młot do złamania bardzo małego orzecha. Po kilku eksperymentach w końcu znalazłem rozwiązanie. Oto jak to zrobiłem.
Powyższy przykład Visual Basic About Visual Basic pokazuje, jak utworzyć TextBox na formularzu, tworząc wystąpienie obiektu, ustawiając właściwości i dodając go do kolekcji Controls, która jest częścią obiektu Form.
Dim txtDataShow As New TextBox
txtDataShow.Height = 19
txtDataShow.Szerokość = 80
txtDataShow.Location = Nowy punkt (X, Y)
Me.Controls.Add(txtDataShow)
Chociaż rozwiązanie Microsoftu tworzy klasę, uznałem, że zamiast tego byłoby możliwe owinięcie tego wszystkiego w podprogramie. Za każdym razem, gdy wywołujesz ten podprogram, tworzysz nowe wystąpienie pola tekstowego w formularzu. Oto pełny kod:
Formularz klasy publicznej 1
Dziedziczy System.Windows.Forms.Form
#Region ' Kod wygenerowany przez projektanta formularzy systemu Windows '
Prywatna subskrypcja BtnStart_Click( _
ByVal nadawca Jako System.Object, _
ByVal e As System.EventArgs) _
Obsługuje btnStart.Kliknij
Dim I jako liczba całkowita
Dim sData As String
Dla I = 1 do 5
sDane = CStr(I)
Zadzwoń do AddDataShow(sData, I)
Następny
Napis końcowy
Sub AddDataShow( _
ByVal sText As String, _
ByVal I jako liczba całkowita)
Dim txtDataShow As New TextBox
Dim UserLft, UserTop As Integer
Dim X, Y jako liczba całkowita
Lft użytkownika = 20
UżytkownikTop = 20
txtDataShow.Height = 19
txtDataShow.Szerokość = 25
txtDataShow.TextAlign = _
Wyrównanie w poziomie.Środek
txtDataShow.BorderStyle = _
BorderStyle.FixedSingle
txtDataShow.Text = sText
X = UżytkownikLft
Y = UserTop + (I - 1) * txtDataShow.Height
txtDataShow.Location = Nowy punkt (X, Y)
Me.Controls.Add(txtDataShow)
Napis końcowy
Koniec klasy
Bardzo dobry punkt, John. Jest to z pewnością o wiele prostsze niż kod Microsoftu ... więc zastanawiam się, dlaczego nalegali na zrobienie tego w ten sposób?
Aby rozpocząć nasze dochodzenie, spróbujmy zmienić jedno z przypisań właściwości w kodzie. Zmieńmy się
txtDataShow.Height = 19
do
txtDataShow.Height = 100
tylko po to, aby upewnić się, że jest zauważalna różnica.
Kiedy ponownie uruchomimy kod, otrzymamy ... Coaaaaa??? ... to samo. Żadnych zmian. W rzeczywistości możesz wyświetlić wartość za pomocą instrukcji, takiej jak MsgBox (txtDataShow.Height), a mimo to otrzymasz 20 jako wartość właściwości, bez względu na to, co do niej przypiszesz. Dlaczego tak się dzieje?
Odpowiedź jest taka, że nie wywodzimy naszej własnej klasy do tworzenia obiektów, po prostu dodajemy rzeczy do innej klasy, więc musimy przestrzegać reguł drugiej klasy. A te reguły stanowią, że nie można zmienić właściwości Height. (No cóż... możesz. Jeśli zmienisz właściwość Multiline na True, możesz zmienić wysokość.)
Dlaczego VB.NET idzie do przodu i wykonuje kod bez nawet skomlenia, że coś może być nie tak, gdy w rzeczywistości całkowicie lekceważy twoje oświadczenie, to zupełnie „kolejny problem”. Mogę jednak zasugerować przynajmniej ostrzeżenie w kompilacji. (Podpowiedź! Podpowiedź! Podpowiedź! Czy Microsoft słucha?)
Przykład z Części I dziedziczy z innej Klasy, a to sprawia, że właściwości są dostępne dla kodu w Klasie dziedziczącej. Zmiana właściwości Height na 100 w tym przykładzie daje oczekiwane rezultaty. (Znowu ... jedno zastrzeżenie: Kiedy tworzona jest nowa instancja dużego komponentu Label, zakrywa ona stary. Aby faktycznie zobaczyć nowe komponenty Label, musisz dodać metodę wywołania aLabel.BringToFront().)
Ten prosty przykład pokazuje, że chociaż MOŻEMY po prostu dodać obiekty do innej Klasy (a czasami jest to właściwe), programowanie kontroli nad obiektami wymaga, abyśmy wyprowadzili je w Klasie i w najbardziej zorganizowany sposób (ośmielę się powiedzieć, „sposób .NET” ??) polega na tworzeniu właściwości i metod w nowej klasie pochodnej w celu zmiany rzeczy. John początkowo nie był przekonany. Powiedział, że jego nowe podejście odpowiada jego celom, mimo że istnieją ograniczenia wynikające z braku „COO” (prawidłowo zorientowanego na obiekt). Niedawno jednak John napisał:
' ... po napisaniu zestawu 5 pól tekstowych w czasie wykonywania, chciałem zaktualizować dane w dalszej części programu - ale nic się nie zmieniło - oryginalne dane nadal tam były.
Odkryłem, że mogę obejść ten problem, pisząc kod, aby zdjąć stare pudełka i włożyć je z powrotem z nowymi danymi. Lepszym sposobem na to byłoby użycie Me.Refresh. Ale ten problem zwrócił moją uwagę na potrzebę dostarczenia metody odejmowania pól tekstowych, a także ich dodawania”.
Kod Johna używał zmiennej globalnej do śledzenia, ile kontrolek zostało dodanych do formularza, więc metoda ...
Prywatny formularz podrzędny1_Load( _
ByVal nadawca Jako System.Object, _
ByVal e As System.EventArgs) _
Obsługuje MyBase.Load
CntlCnt0 = Me.Controls.Count
Napis końcowy
Wtedy 'ostatnią' kontrolkę można było usunąć...
N = Me.Controls.Count - 1
Me.Controls.RemoveAt(N)
John zauważył, że „może to trochę niezdarne”.
W ten sposób Microsoft śledzi obiekty w COM I w ich „brzydkim” przykładowym kodzie powyżej.
Wróciłem teraz do problemu dynamicznego tworzenia kontrolek w formularzu w czasie wykonywania i ponownie przeglądałem artykuły „Co się stało z tablicami kontrolnymi”.
Utworzyłem klasy i mogę teraz umieścić kontrolki w formularzu tak, jak chcę.
John zademonstrował, jak sterować rozmieszczeniem kontrolek w polu grupy przy użyciu nowych klas, których zaczął używać. Może jednak Microsoft miał rację w swoim „brzydkim” rozwiązaniu!