Emulare in VB.Net un vettore di controlli (tipo VB6)

Come si fa a emulare in VB.Net un vettore di controlli? Ammesso e non concesso che ne valga davvero la pena, ci possono essere dei casi in cui questo sistema sia davvero utile.

Come nel caso del problema posto da un membro della Mailing List, che stava creando uno UserControl con due pulsanti e voleva passare al container il numero indicativo del pulsante premuto, l'Index del vecchio VB6.

Io gli ho indicato con una certa sicumera che avrebbe dovuto creare una classe di tipo EventArgs ed aggiungere la proprietà Index, implementando poi Delegate ed Event, per poter scatenare l'evento nel container in modo coerente con la sua impostazione.

Però poi mi sono chiesto se non ero stato 'troppo' sicuro di me. Dopotutto, non avevo mai creato uno usercontrol, nemmeno in VB6. Così mi sono messo a provare, ed ho imparato altre cose nuove.

  •  Ho aperto Visual Studio 2005;
  •  da esso ho aperto il mio solito progetto 'ProveVarie', in cui faccio i miei esperimenti;
  •  ho aggiunto al progetto uno UserControl, chiamandolo DuePulsanti;
  •  ci ho inserito una TextBox (txtTesto), e due Button (btnUno e btnDue);
  •  ho fatto doppio clic su uno dei pulsanti per andare nell'editor di codice per il suo evento Click;
  •  ho cambiato il nome della sub e aggiunto la gestione dell'evento Click dell'altro pulsante:
  Private Sub ButtonClick(ByVal sender As System.Object, ByVal e As System.EventArgs) _
                                                   Handles btnUno.Click, btnDue.Click

Pensando che, nella pratica normale, è probabile che i pulsanti (o altri tipi di controllo) possano essere anche più di due, e che potrebbero nel tempo anche cambiare di numero, ho ragionato che non sarebbe stato pratico usare, per identificare il pulsante premuto, la proprietà .Tag, che è invece comodissima in moltissimi casi.
Nemmeno il sender.Name sarebbe stata una buona soluzione (che è poi quella contenuta nella risposta da me data al messaggio di cui all'inizio).
La soluzione più elegante era una enumerazione. Così ho studiato anche quella ed eccola qua, inserita nel codice della DuePulsanti:

  Enum Pulsante As Integer
    btnUno
    btnDue
  End Enum

A questo punto, ho implementato la classe per l'argomento dell'evento, ereditando da System.EventArgs e aggiungendo la proprietà Index ed un costruttore con il suo valore come parametro richiesto:

Public Class DuePulsantiButtonClickEventArgs
  Inherits System.EventArgs
  Private mIndex As Integer
  Public ReadOnly Property Index() As Integer
    Get
      Return Me.mIndex
    End Get
  End Property
  Public Sub New(ByVal index As Integer)
    Me.mIndex = index
  End Sub
End Class

Quindi ho creato il Delegate e il suo Event (nell'ordine):

  Public Delegate Sub DuePulsantiButtonClickEventHandler(ByVal sender As Object, _
                                                         ByVal e As DuePulsantiButtonClickEventArgs)
  Public Event DuePulsantiButtonClick As DuePulsantiButtonClickEventHandler

Infine, mi sono divertito a sviluppare il codice della Sub ButtonClick, sfruttando le possibilità offerte dalla classe Enum:

    Dim p As String = DirectCast(sender, Button).Name
    Me.txtTesto.Text = p
    Select Case p
      Case [Enum].GetName(GetType(Pulsante), Pulsante.btnUno)
        RaiseEvent DuePulsantiButtonClick(Me, _
                                          New DuePulsantiButtonClickEventArgs(Pulsante.btnUno))
      Case [Enum].GetName(GetType(Pulsante), Pulsante.btnDue)
        RaiseEvent DuePulsantiButtonClick(Me, _
                                          New DuePulsantiButtonClickEventArgs(Pulsante.btnDue))
    End Select

Prima ho ottenuto il nome del sender e l'ho scritto nella TextBox, poi ho aperto su di esso un costrutto Select Case. Per non arrabbattarmi a cercare il nome esatto dei due pulsanti, per fare il confronto, ho usato il metodo GetName della classe Enum (il cui nome, essendo Enum una parola riservata in Visual Basic, deve essere racchiuso tra parentesi quadre), fornendo il tipo dell'enumerazione, espresso con GetType(Pulsante), e il valore (espresso attraverso l'enumerazione stessa!) dell'elemento dell'enumerazione di cui voglio il nome.
Se non vi è venuto mal di testa, rileggete piano e magari seguite una delle righe dove viene usato il metodo Getname.

A questo punto c'era solo da far la prova. Compilazione... perfetto al primo colpo (fattore C, naturalmente). La classe DuePulsanti compare nella ToolBox.
Allora ho aggiunto una scheda di nome UserControls e ci ho trascinato la classe appena creata. Poi:

  •  ho aperto una delle form di collaudo
  •  ci ho inserito un DuePulsanti, chiamandolo ucDuePulsanti
  •  ho fatto doppio clic su uo dei pulsanti per andare nel codice, ma ne è venuto fuori tutt'altro da quel che mi aspettavo, per cui ho cancellato il codice
  •  ho scelto nelle due combo in alto il controllo ucDuePulsanti ed il suo evento DuePulsantiButtonClick
  •  ho digitato il codice:
  Private Sub ucDuePulsanti_DuePulsantiButtonClick(ByVal sender As Object, ByVal e As DuePulsantiButtonClickEventArgs) _
Handles ucDuePulsanti.DuePulsantiButtonClick MessageBox.Show("Hai premuto il pulsante " & e.Index.ToString, _ "Messaggio dallo user control") End Sub

Troooppo facile, una volta che si ha imparato...

Print | posted @ domenica 7 gennaio 2007 04:25

Comments on this entry:

Gravatar # re: Emulare in VB.Net un vettore di controlli (tipo VB6)
by Alessandro Del Sole at 07/01/2007 04:49

L'ennesima dimostrazione di come in VB 2005 sia molto più facile realizzare procedure rispetto a VB 6... ;-)
Speriamo che questi spunti invoglino a provare il nuovo! ;-)
Ale
Gravatar # re: Emulare in VB.Net un vettore di controlli (tipo VB6)
by Diego x Alessandro at 09/01/2007 21:06

In effetti, costruire un 'proprio' user control è enormemente più facile e 'chiaro' in VB.Net che in VB6. Decisamente.
Gravatar # re: Emulare in VB.Net un vettore di controlli (tipo VB6)
by Marco Podda at 23/12/2010 17:26

Sarà anche più facile, come dice Alessandro, ma non ho ancora trovato in giro il modo di "emulare" in VB.NET le funzionalità native di VB che permettono di caricare a run time uno o piu' controlli in una matrice di controlli facendo in modo che l'elemento caricati erediti automaticamente la configurazione del controllo base di partenza (ossia, se Label(0) è l'elemento base della matrice, posso ottenere Label(1) facendo Load Label(Label.UBound+1)
Io facevo uso ed abuso di matrici di controlli e .NET ha "segato" questa caratteristica davvero formidabile. Chiaramente, per un sistema di sviluppo orientato allo sviluppo di applicazioni web, non e' importante che vi siano matrici di controlli, ma visto che ci si possono fare anche applicazioni desktop cosa gli costava mantenere questa caratteristica?
Gravatar # re: Emulare in VB.Net un vettore di controlli (tipo VB6)
by d.cattaruzza at 08/01/2011 13:43

Marco, quand'anche fosse possibile usare 'Load Label(1)', dovresti comunque impostarne le proprietà di collocazione e di visibilità. In .Net, puoi creare un controllo e aggiungerne il riferimento all'insieme Controls. Poi - se proprio vuoi - puoi aggiungerne il riferimento anche a un insieme, come una List(Of T). Ciò che si vuole sottolineare è che in OOP un insieme di controlli come in VB6 è molto raramente, ma molto raramente utile. E' il modo di vedere e usare l'insieme che diventa diverso.
Comments have been closed on this topic.