Descrizione :
Alcuni miei suggerimenti in merito al ricorrente problema delle Matrici Di Controlli "in salsa VB.NET".
+ Articolo :
Uno dei primi scogli che contribuiscono ad affondare gli entusiasmi dei neo-VB.NET/ex-VB6, è la totale assenza della vecchia "Matrice di Controlli."
Creando ad esempio una Label su Form, e facendo copia/incolla della stessa, NON uscirà più quel classico messaggio : "... creare una matrice di controlli ?".
Personalmente sono d'accordo con i molti che sostengono sia un bene.
Di contaminazioni ex-VB6 ce ne sono fin troppe : almeno questa se la sono risparmiata.
In questo Articolo voglio mostrare alcune tecniche che permettono di raggiungere e superare la gestione di Matrici di Controlli, anche grazie all'utilizzo di LINQ e delle Regular Expressions.
Ovviamente l'uso delle matrici in VB6 è più immediato, ma come spesso accade in VB.NET, ciò che alle prime sembra essere un po' più complesso del dovuto, poi permette di andare ben più lontano.
Ho deciso di raggruppare il tutto in 2 Esempi principali.
Ad ogni Esempio fa capo una Form.
Perciò avremo due Form : FormMainA e FormMainB.
La semplicità della struttura delle Form non rende necessaria alcuna immagine particolare.
1. FormMainA :
Nel primo esempio ho 5 Button su Form e un buon numero di Label.
Consiglio di avere almeno una dozzina di Label.
Lo scopo è gestire solo il gruppo di Label in modo centralizzato ( la matrice ) in modo che possano essere ordinate in base ad una o più Proprietà.
Tra i vari vantaggi, matriceLabels permette di definire a piacere uno o più criteri di ordinamento delle Labels all'interno della Matrice ossia l'ordine in cui verranno prese in un normale ciclo.
La cosa si ottiene semplicemente con i Metodi OrderBy, OrderByDescending, ThenBy, ThenByDescending.
Per semplicità gestisco solo l'Evento Click su tutte le Label presenti.
--> Codice FormMainA :
Public Class FormMainA Private matriceLabels As New List(Of Label) Private Sub matriceLabelsClick(ByVal sender As System.Object, ByVal e As System.EventArgs) MessageBox.Show("Click su " & DirectCast(sender, Label).Name) End Sub Private Sub FormMainA_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load For Each C As Control In Me.Controls If TypeOf C Is Label Then matriceLabels.Add(C) AddHandler C.Click, AddressOf matriceLabelsClick End If Next End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'Ordina per nome ASC matriceLabels = matriceLabels.OrderBy(Function(L) L.Name).ToList() End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click 'Ordina per nome DESC matriceLabels = matriceLabels.OrderByDescending(Function(L) L.Name).ToList() End Sub Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click 'Ordina per nome { [parte letterale]-[parte numerica] } matriceLabels = matriceLabels.OrderBy(Function(C) System.Text.RegularExpressions.Regex.Match(C.Name, "(?:(?<nome>[\p{L}]+))").Groups("nome").Value) _ .ThenBy(Function(C) Convert.ToInt32(System.Text.RegularExpressions.Regex.Match(C.Name, "\d+$").Value)) _ .ToList() End Sub Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click 'Ordina per Colonne e Righe matriceLabels = matriceLabels.OrderBy(Function(L) L.Top).ThenBy(Function(L) L.Left).ToList() End Sub Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click 'Test ordinamento For i As Integer = 0 To matriceLabels.Count - 1 matriceLabels(i).Text = i Next End Sub End Class
Basta uno sguardo alla semplicità dei Metodi LINQ di ordinamento OrderBy, OrderByDescending, ThenBy, ecc., e direi che il confronto con VB6 ce lo siamo già giocato.
- La funzione di Button1 e Button2 è chiara.
- La funzione di Button3 è quella di ottenere un ordinamento per Nome, ma rispettando la suddivisione interna dei nomi che VB assegna di default ad ogni nuovo controllo aggiunto in Design { Label1, Label2, ..., LabelN }, cosa che invece non accade nei precedenti due casi, dove il nome del controllo viene inteso nel suo senso letterale, e quindi ad esempio "Label10" verrebbe subito dopo "Label1".
- La funzione di Button4 è quella di ordinare per posizione. Se i controlli sono disposti in modo opportuno si otterrà un ordinamento per Righe ( dall'alto in basso ) e per Colonne ( da sinsitra a destra ).
- La funzione del Button5 è di testare i vari ordinamenti scrivendo nel controllo l'indice che lo stesso ha in matrice.
2. FormMainB :
Nel secondo esempio le cose si fanno ancora più interessanti.
Voglio una Matrice di Controlli eterogenea, ossia costituita da due o più tipi di controllo.
Anche qui per semplicità avrò una Form con un Button e due gruppi : Label e TextBox.
E decido che le TextBox abbiano la precedenza sulle Label.
Al solito gestisco Click e ordino per Nome, rispettando l'ordine numerico assegnato da VB.
--> Codice FormMainB :
Public Class FormMainB Private matriceControlli As New List(Of Control) Private Sub matriceControlliClick(ByVal sender As System.Object, ByVal e As System.EventArgs) MessageBox.Show("Click su " & DirectCast(sender, Control).Name) End Sub Private Sub FormMainB_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load matriceControlli.AddRange(Me.Controls.OfType(Of TextBox)()) matriceControlli.AddRange(Me.Controls.OfType(Of Label)()) For Each C As Control In matriceControlli AddHandler C.Click, AddressOf matriceControlliClick Next End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click '1. Definisco l'ordine con cui prendere in considerazione i controlli, a seconda della tipologia Dim OrdineControlli As New Dictionary(Of Type, Integer) OrdineControlli.Add(GetType(TextBox), 1) OrdineControlli.Add(GetType(Label), 2) '2. Impongo il nuovo ordine matriceControlli = matriceControlli.OrderBy(Function(C) OrdineControlli(C.GetType)) _ .ThenBy(Function(C) System.Text.RegularExpressions.Regex.Match(C.Name, "(?:(?<nome>[\p{L}]+))").Groups("nome").Value) _ .ThenBy(Function(C) Convert.ToInt32(System.Text.RegularExpressions.Regex.Match(C.Name, "\d+$").Value)) _ .ToList 'Test sull'ordine imposto alla matrice di controlli For i As Integer = 0 To matriceControlli.Count - 1 matriceControlli(i).Text = i Next End Sub End Class
Alla matrice aggiungo i controlli desiderati per gruppi, naturalmente escludendo il Button.
Non mi soffermo ad approfondire oltre l'uso di LINQ e di System.Text.RegularExpressions.
Direi che per l'argomento "Matrici di Controlli" di spunti utili ce ne sono.
+ Fine Articolo.
0 commenti:
Posta un commento