Oggetti del form dinamici

di il
26 risposte

Oggetti del form dinamici

Salve, sono nuovo del forum e chiedo scusa in anticipo nel caso in cui sia già stata aperta una discussione simile alla mi, tuttavia controllando non mi pare di aver trovato una cosa simile.
Detto ciò, vi espongo il mio problema.
Ho il mio form con un bel po’ di textbox, label e datetimepicker allineate (cioè 1 txt, 1 lbl e 1 dtm per ciascuna “riga” e poi si passa alla riga successiva).
Tutti questi oggetti hanno la proprietà visible = false

Dovrei fare in modo che all’inserimento di un numero, esempio 6, le prime 6 txt cambino la proprietà visible a true.
Ovviamente è una cosa molto stupida e lunga scrivere manualmente txt1, txt2, txt3.visible=true ecc...
Perciò pensavo fosse opportuno fare un ciclo che modifichi tale proprietà in base al nome dell’oggetto (cioè creo una variabile di tipo stringa uguale al nome dell’oggetto, che cambia di volta in volta, e modifico la txt del mio form che ha il nome uguale a quella stringa)

Spero di aver reso l’idea di cosa mi serve, quantomeno concettualmente.
Ho già cercato mille cose su internet e molti codici per quando mi sembrassero sensati si sono sempre rivelati non funzionanti. È tutto il pomeriggio che ci sto dietro e non ne sono venuto a capo.
Spero che possiate aiutarmi, grazie mille

26 Risposte

  • Re: Oggetti del form dinamici

    andrea25 ha scritto:


    Perciò pensavo fosse opportuno fare un ciclo che modifichi tale proprietà in base al nome dell’oggetto (cioè creo una variabile di tipo stringa uguale al nome dell’oggetto, che cambia di volta in volta, e modifico la txt del mio form che ha il nome uguale a quella stringa)
    mi sembra la strada giusta, ti dispiace mostrare i tuoi tentativi ?
    Dai un'occhiata a Controls.Find
  • Re: Oggetti del form dinamici

    andrea25 ha scritto:


    Perciò pensavo fosse opportuno fare un ciclo che modifichi tale proprietà in base al nome dell’oggetto (cioè creo una variabile di tipo stringa uguale al nome dell’oggetto, che cambia di volta in volta, e modifico la txt del mio form che ha il nome uguale a quella stringa)
    Questa è una idea.

    In alternativa, potresti eseguire la ricerca per nome allo scopo di costruirti un "dizionario" o qualcosa di simile, da utilizzare in seguito per semplificare e velocizzare l'accesso al componente desiderato utilizzando criteri diversi dal nome, ad esempio degli oggetti con proprietà addizionali significative e magari LINQ per risalire al controllo che ti serve. Questo perché, se i controlli sono tanti, la ricerca continuativa per nome potrebbe essere lenta.

    Ciao!
  • Re: Oggetti del form dinamici

    Ci sono vari approci, mettere i controlli in una lista, usare matrici di controlli, programmare degli user control.
    Nel tuo caso senza stravolgere quello che hai fatto è sufficiente usare la proprietà Tag di ogni controllo.
    Altra cosa che devi fare per evitare di ciclare controlli sul form che non sono coinvolti è mettere tutti i controlli interessati in un panel.
    In progettazione inserisci a mano in ogni Tag il numero progressivo voluto, per esempio txt, lbl e dtm che sono nella riga 1 nel Tag metti 1, quelli che sono nella riga 2 nel Tag metti 2 ecc ecc.
    Poi esegui il ciclo come hai già intuito.
    
            Dim Visibili As Byte = 3 ' righe che saranno visibili
            For Each controllo In Panel1.Controls
                If controllo.tag > Visibili Then controllo.visible = False Else controllo.visible = True
            Next
    
    Per iserire i giusti Tag, puoi usare la multiselezione, selezioni tutti i controlli in una riga e inserisci il Tag, così lo scrivi una volta soltanto per ogni riga.
  • Re: Oggetti del form dinamici

    patel ha scritto:


    andrea25 ha scritto:


    Perciò pensavo fosse opportuno fare un ciclo che modifichi tale proprietà in base al nome dell’oggetto (cioè creo una variabile di tipo stringa uguale al nome dell’oggetto, che cambia di volta in volta, e modifico la txt del mio form che ha il nome uguale a quella stringa)
    mi sembra la strada giusta, ti dispiace mostrare i tuoi tentativi ?
    Dai un'occhiata a Controls.Find
    Purtroppo non ho il lavoro sottomano perciò non riesco ad elencare tutti i metodi che avevo provato, ma andando un po' a memoria ricordo che avevo provato:

    For i = Label1.TabIndex To Label3.TabIndex

    For Each myControl As Control In Controls.OfType(Of Label)()
    If myControl.TabIndex.Equals(i) Then
    myControl.Text = ""
    End If
    Next
    Chiudendo poi il ciclo For con Next.

    Next

    questo era un esempio per le label.text ma non ha funzionato, mi dava errore su myControl (e Controls.OfType se non ricordo male).


    ricordo di aver usato anche il controls.find ma non ha funzionato e non capisco il perchè:
    praticamente cercavo la textbox di nome "txt1", riuscivo a trovarla, ma non riuscivo a modificarne le proprietà. ad esempio variabile.visible = true non mi dava nulla, ma se facevo un messagebox.show di variabile.name mi appariva "txt1".
    praticamente mi intercettava l'oggetto e basta se non erro.

    capisco che sia difficile da capire senza mostrare il codice ma purtroppo non riesco a reperirlo al momento,
  • Re: Oggetti del form dinamici

    Alka ha scritto:


    andrea25 ha scritto:


    Perciò pensavo fosse opportuno fare un ciclo che modifichi tale proprietà in base al nome dell’oggetto (cioè creo una variabile di tipo stringa uguale al nome dell’oggetto, che cambia di volta in volta, e modifico la txt del mio form che ha il nome uguale a quella stringa)
    Questa è una idea.

    In alternativa, potresti eseguire la ricerca per nome allo scopo di costruirti un "dizionario" o qualcosa di simile, da utilizzare in seguito per semplificare e velocizzare l'accesso al componente desiderato utilizzando criteri diversi dal nome, ad esempio degli oggetti con proprietà addizionali significative e magari LINQ per risalire al controllo che ti serve. Questo perché, se i controlli sono tanti, la ricerca continuativa per nome potrebbe essere lenta.

    Ciao!
    Purtroppo non ho mai usato LINQ e quindi non saprei nemmeno da dove iniziare
  • Re: Oggetti del form dinamici

    Rubik ha scritto:


    Ci sono vari approci, mettere i controlli in una lista, usare matrici di controlli, programmare degli user control.
    Nel tuo caso senza stravolgere quello che hai fatto è sufficiente usare la proprietà Tag di ogni controllo.
    Altra cosa che devi fare per evitare di ciclare controlli sul form che non sono coinvolti è mettere tutti i controlli interessati in un panel.
    In progettazione inserisci a mano in ogni Tag il numero progressivo voluto, per esempio txt, lbl e dtm che sono nella riga 1 nel Tag metti 1, quelli che sono nella riga 2 nel Tag metti 2 ecc ecc.
    Poi esegui il ciclo come hai già intuito.
    
            Dim Visibili As Byte = 3 ' righe che saranno visibili
            For Each controllo In Panel1.Controls
                If controllo.tag > Visibili Then controllo.visible = False Else controllo.visible = True
            Next
    
    Per iserire i giusti Tag, puoi usare la multiselezione, selezioni tutti i controlli in una riga e inserisci il Tag, così lo scrivi una volta soltanto per ogni riga.
    grazie, oggi pomeriggio proverò con questo metodo, tuttavia ho un dubbio:
    quando avevo provato a fare un ciclo for each controllo in me.controls (non avevo inserito ilpanel), non riuscivo ad intercettare le textbox...
    Oggi pomeriggio riproverò aggiungendo un panel.
    Grazie mille.
  • Re: Oggetti del form dinamici

    andrea25 ha scritto:


    Purtroppo non ho mai usato LINQ e quindi non saprei nemmeno da dove iniziare
    Al netto che ti sono state date una quantità di alternative massiccia, se non hai mai usato LINQ, per iniziare... studia LINQ.
  • Re: Oggetti del form dinamici

    andrea25 ha scritto:


    quando avevo provato a fare un ciclo for each controllo in me.controls (non avevo inserito ilpanel), non riuscivo ad intercettare le textbox...
    Questo perché le TextBox - se sono contenute nel Panel - fanno parte della collezione Controls del pannello, e non del Form: ogni controllo ha la sua collezione degli altri controlli che stanno all'interno.
  • Re: Oggetti del form dinamici

    andrea25 ha scritto:


    questo era un esempio per le label.text ma non ha funzionato, mi dava errore su myControl (e Controls.OfType se non ricordo male).
    ricordo di aver usato anche il controls.find ma non ha funzionato e non capisco il perchè:
    Tutti gli esempi o approci che ti hanno consigliato o hai tentato devono funzionare, se non sei riuscito hai sbagliato la sintassi, oppure cercavi un controllo dove non c'era.

    Ti informo che in VB.Net, ma anche in C#, i controlli sono sempre parte di matrici, il problema è che l'indice è determinato dalla posizione nel designer e che tale posizione non dipende da quando il controllo è stato inserito, ma è arbitrario, si potrebbero riordinare i controlli nel designer, ma poi ad ogni nuovo inserimento in progettazione, l'indice potrebbe cambiare, generando sicuri malfunzionameti, per questo è sconsiglaiato.

    Ma l'approcio più logico per un programmatore che ha 20, 30, 40 Text, gestibili con dei cicli, è avere le text in una matrice e identificarle con l'indice.

    Per avere la certezza che una text o qualsiasi altro controllo, posizionati sul form abbiano sempre lo stesso indice è crearli e posizionarli in runtime.
    
    Public Class Form1
    
        Dim TextIN(19) As TextBox ' matrice di Text
        Dim Label1(19) As Label ' matrice di Label
        Dim Label2(19) As Label ' matrice di Label
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Size = New Size(470, 554)
            ' riempio tre Array di controlli e li aggiungo al Form
            For riga = 0 To 19
                TextIN(riga) = New TextBox ' creo le textbox
                TextIN(riga).Name = "TexIN" & riga.ToString("00") ' nome composto
                TextIN(riga).Left = 10
                TextIN(riga).Top = 10 + riga * 25
                TextIN(riga).Tag = riga ' fa comodo per risolvere l'indice
                Me.Controls.Add(TextIN(riga)) ' aggiungo la text
                AddHandler TextIN(riga).Click, AddressOf TextIN_OnClick ' permette di avere l'evento click
    
                Label1(riga) = New Label ' creo le label1
                Label1(riga).Name = "Label1" & riga.ToString("00") ' nome composto
                Label1(riga).Left = 120
                Label1(riga).Top = 10 + riga * 25
                Label1(riga).Tag = riga ' fa comodo per risolvere l'indice
                Label1(riga).BackColor = Color.LightGray
                Me.Controls.Add(Label1(riga)) ' aggiungo la text
                AddHandler Label1(riga).Click, AddressOf Label1_OnClick ' permette di avere l'evento click
    
                Label2(riga) = New Label ' creo le label2
                Label2(riga).Name = "Label2" & riga.ToString("00") ' nome composto
                Label2(riga).Left = 230
                Label2(riga).Top = 10 + riga * 25
                Label2(riga).Tag = riga ' fa comodo per risolvere l'indice
                Label2(riga).BackColor = Color.WhiteSmoke
                Label2(riga).AutoSize = True
                Me.Controls.Add(Label2(riga)) ' aggiungo la text
                AddHandler Label2(riga).Click, AddressOf Label2_OnClick ' permette di avere l'evento click
            Next riga
    
            ' posso usare i cicli per modificare qualsiasi proprietà
            For rig = 0 To 19
                Label1(rig).Text = "cliccami"
                TextIN(rig).Text = "scrivi su " & TextIN(rig).Name
            Next rig
        End Sub
    
        Private Sub TextIN_OnClick(ByVal sender As System.Object, ByVal e As System.EventArgs)
            ' solo d'esempio
            Dim ClicX As Integer = sender.Left ' coordinata X della text cliccata
            Dim ClicY As Integer = sender.Top ' coordinata Y della text cliccata
            Dim Indice As Integer = sender.tag() ' indice della text cliccata
            Dim NomeText As String = sender.name ' nome della Text
            sender.text = "cliccato " & Indice.ToString("00")
            Me.Text = "riga " & Indice
        End Sub
    
        Private Sub Label1_OnClick(ByVal sender As System.Object, ByVal e As System.EventArgs)
            ' solo d'esempio
            Dim ClicX As Integer = sender.Left ' coordinata X della Label1 cliccata
            Dim ClicY As Integer = sender.Top ' coordinata Y della Label1 cliccata
            Dim Indice As Integer = sender.tag() ' indice della Label1 cliccata
            Dim NomeLabel1 As String = sender.name ' nome della Label1
            sender.text = "cliccato"
            ' con gli indici si schiude un mondo
            Label2(Indice).Text = "nella " & TextIN(Indice).Name & " c'è scritto:  " & TextIN(Indice).Text
            Me.Text = "riga " & Indice
        End Sub
    
        Private Sub Label2_OnClick(ByVal sender As System.Object, ByVal e As System.EventArgs)
            ' solo d'esempio
            Dim ClicX As Integer = sender.Left ' coordinata X della Label2 cliccata
            Dim ClicY As Integer = sender.Top ' coordinata Y della Label2 cliccata
            Dim Indice As Integer = sender.tag() ' indice della Label2 cliccata
            Dim NomeLabel1 As String = sender.name ' nome della Label2
            sender.text = "cliccato"
            Me.Text = "riga " & Indice
        End Sub
    
    End Class
    
    Con tale approcio, non dovrai ogni volta cercare il controllo giusto con For Each.

    Quando avrai necessità più articolate, ti consiglio di guardarti come si crea e si usa un UserControl.
    Ora sarebbe fuori argomento.
  • Re: Oggetti del form dinamici

    Alka ha scritto:


    andrea25 ha scritto:


    quando avevo provato a fare un ciclo for each controllo in me.controls (non avevo inserito ilpanel), non riuscivo ad intercettare le textbox...
    Questo perché le TextBox - se sono contenute nel Panel - fanno parte della collezione Controls del pannello, e non del Form: ogni controllo ha la sua collezione degli altri controlli che stanno all'interno.
    Grazie mille a tutti per le risposte, alla fine sono riuscito a risolvere mettendo le textbox all’interno del panel e fare il ciclo come suggerito da Alka.

    Poi avevo un altro dubbio, supponendo che io voglia lasciare lo stesso tag a tutti gli elementi della stessa riga, se poi volessi fare un altro ciclo ma relativo alle singole label o alle singole textbox, potrebbe andar bene un codice del tipo:
    For each variabile as label in panel.controls

    Next
    ?
  • Re: Oggetti del form dinamici

    Rubik ha scritto:


    andrea25 ha scritto:


    questo era un esempio per le label.text ma non ha funzionato, mi dava errore su myControl (e Controls.OfType se non ricordo male).
    ricordo di aver usato anche il controls.find ma non ha funzionato e non capisco il perchè:
    Tutti gli esempi o approci che ti hanno consigliato o hai tentato devono funzionare, se non sei riuscito hai sbagliato la sintassi, oppure cercavi un controllo dove non c'era.

    Ti informo che in VB.Net, ma anche in C#, i controlli sono sempre parte di matrici, il problema è che l'indice è determinato dalla posizione nel designer e che tale posizione non dipende da quando il controllo è stato inserito, ma è arbitrario, si potrebbero riordinare i controlli nel designer, ma poi ad ogni nuovo inserimento in progettazione, l'indice potrebbe cambiare, generando sicuri malfunzionameti, per questo è sconsiglaiato.

    Ma l'approcio più logico per un programmatore che ha 20, 30, 40 Text, gestibili con dei cicli, è avere le text in una matrice e identificarle con l'indice.

    Per avere la certezza che una text o qualsiasi altro controllo, posizionati sul form abbiano sempre lo stesso indice è crearli e posizionarli in runtime.
    
    Public Class Form1
    
        Dim TextIN(19) As TextBox ' matrice di Text
        Dim Label1(19) As Label ' matrice di Label
        Dim Label2(19) As Label ' matrice di Label
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Size = New Size(470, 554)
            ' riempio tre Array di controlli e li aggiungo al Form
            For riga = 0 To 19
                TextIN(riga) = New TextBox ' creo le textbox
                TextIN(riga).Name = "TexIN" & riga.ToString("00") ' nome composto
                TextIN(riga).Left = 10
                TextIN(riga).Top = 10 + riga * 25
                TextIN(riga).Tag = riga ' fa comodo per risolvere l'indice
                Me.Controls.Add(TextIN(riga)) ' aggiungo la text
                AddHandler TextIN(riga).Click, AddressOf TextIN_OnClick ' permette di avere l'evento click
    
                Label1(riga) = New Label ' creo le label1
                Label1(riga).Name = "Label1" & riga.ToString("00") ' nome composto
                Label1(riga).Left = 120
                Label1(riga).Top = 10 + riga * 25
                Label1(riga).Tag = riga ' fa comodo per risolvere l'indice
                Label1(riga).BackColor = Color.LightGray
                Me.Controls.Add(Label1(riga)) ' aggiungo la text
                AddHandler Label1(riga).Click, AddressOf Label1_OnClick ' permette di avere l'evento click
    
                Label2(riga) = New Label ' creo le label2
                Label2(riga).Name = "Label2" & riga.ToString("00") ' nome composto
                Label2(riga).Left = 230
                Label2(riga).Top = 10 + riga * 25
                Label2(riga).Tag = riga ' fa comodo per risolvere l'indice
                Label2(riga).BackColor = Color.WhiteSmoke
                Label2(riga).AutoSize = True
                Me.Controls.Add(Label2(riga)) ' aggiungo la text
                AddHandler Label2(riga).Click, AddressOf Label2_OnClick ' permette di avere l'evento click
            Next riga
    
            ' posso usare i cicli
            For rig = 0 To 19
                Label1(rig).Text = "cliccami"
                TextIN(rig).Text = "scrivi su " & TextIN(rig).Name
            Next rig
        End Sub
    
        Private Sub TextIN_OnClick(ByVal sender As System.Object, ByVal e As System.EventArgs)
            ' solo d'esempio
            Dim ClicX As Integer = sender.Left ' coordinata X della text cliccata
            Dim ClicY As Integer = sender.Top ' coordinata Y della text cliccata
            Dim Indice As Integer = sender.tag() ' indice della text cliccata
            Dim NomeText As String = sender.name ' nome della Text
            sender.text = "cliccato " & Indice.ToString("00")
            Me.Text = "riga " & Indice
        End Sub
    
        Private Sub Label1_OnClick(ByVal sender As System.Object, ByVal e As System.EventArgs)
            ' solo d'esempio
            Dim ClicX As Integer = sender.Left ' coordinata X della Label1 cliccata
            Dim ClicY As Integer = sender.Top ' coordinata Y della Label1 cliccata
            Dim Indice As Integer = sender.tag() ' indice della Label1 cliccata
            Dim NomeLabel1 As String = sender.name ' nome della Label1
            sender.text = "cliccato"
            ' con gli indici si schiude un mondo
            Label2(Indice).Text = "nella " & TextIN(Indice).Name & " c'è scritto:  " & TextIN(Indice).Text
            Me.Text = "riga " & Indice
        End Sub
    
        Private Sub Label2_OnClick(ByVal sender As System.Object, ByVal e As System.EventArgs)
            ' solo d'esempio
            Dim ClicX As Integer = sender.Left ' coordinata X della Label2 cliccata
            Dim ClicY As Integer = sender.Top ' coordinata Y della Label2 cliccata
            Dim Indice As Integer = sender.tag() ' indice della Label2 cliccata
            Dim NomeLabel1 As String = sender.name ' nome della Label2
            sender.text = "cliccato"
            Me.Text = "riga " & Indice
        End Sub
    
    End Class
    
    Con tale approcio, non dovrai ogni volta cercare il controllo giusto con For Each.

    Quando avrai necessità più articolate, ti consiglio di guardarti come si crea e si usa un UserControl.
    Ora sarebbe fuori argomento.
    Grazie mille, ho già risolto con l'altro metodo tuttavia leggendo il tuo codice mi era venuto un dubbio:
    Inserendo gli oggetti in questa maniera non c'è il rischio che poi possa avere dei problemi di adattabilità nel caso in cui facessi girare il mio programma su schermi diversi o se cercassi di rimpicciolirlo?
    Chiedo per una mia curiosità più che altro.
  • Re: Oggetti del form dinamici

    andrea25 ha scritto:



    Poi avevo un altro dubbio, supponendo che io voglia lasciare lo stesso tag a tutti gli elementi della stessa riga, se poi volessi fare un altro ciclo ma relativo alle singole label o alle singole textbox, potrebbe andar bene un codice del tipo:
    For each variabile as label in panel.controls

    Next
    ?
    la sintassi giusta è:
    
          For Each controllo In Panel1.Controls
                If controllo.GetType Is GetType(Label) Then
                   ' tuo codice ......
                End If
          Next
    
  • Re: Oggetti del form dinamici

    Rubik ha scritto:


    andrea25 ha scritto:



    Poi avevo un altro dubbio, supponendo che io voglia lasciare lo stesso tag a tutti gli elementi della stessa riga, se poi volessi fare un altro ciclo ma relativo alle singole label o alle singole textbox, potrebbe andar bene un codice del tipo:
    For each variabile as label in panel.controls

    Next
    ?
    la sintassi giusta è:
    
          For Each controllo In Panel1.Controls
                If controllo.GetType Is GetType(Label) Then
                   ' tuo codice ......
                End If
          Next
    
    Perfetto, grazie
  • Re: Oggetti del form dinamici

    andrea25 ha scritto:


    Grazie mille, ho già risolto con l'altro metodo tuttavia leggendo il tuo codice mi era venuto un dubbio:
    Inserendo gli oggetti in questa maniera non c'è il rischio che poi possa avere dei problemi di adattabilità nel caso in cui facessi girare il mio programma su schermi diversi o se cercassi di rimpicciolirlo?
    Chiedo per una mia curiosità più che altro.
    Si, il metodo che ti ho proposto nel POST: 01 ott 2020, 11:07, come già ti sei accorto comporta altri controlli nel ciclo For Each se vuoi fare anche altre cose e l'esempio delle matrici era solo un'altro metodo per aumentare la flessibilità, ma ci sono altre decine di approci tutti validi che si scelgono in base alle esigenze.
    Se inserisci i controlli da progettazione o da codice, non cambia nulla, i problemi di ridimensionamento, sono gli stessi.
    E' buona norma inserire i controlli in un panel che poi ancori al form come desiderato, guarda anche FlowLayoutPanel che ti permette di inserire controlli anche oltre la capacità del Form, quando ridimensioni e i controlli non possono essere visualizzati tutti appaiono le scrollbar.
    Ma anche SplitContainer è molto utile per gestire i controlli in un form di dimensioni dinamiche.
Devi accedere o registrarti per scrivere nel forum
26 risposte