Newsgroup: it.comp.lang.visual-basic
Titolo: Problemi .Net e sub

Ciao a tutti,
   volevo una info velocissima e cercherò di spiegarla in modo chiaro....
Ho una form chiamata MiaForm con una sub chiamata Pippo e una casella di
testo chiamata pluto ( che fantasia )
Adesso creo un modulo e un modulo di classe chiamati nell'ordine ModA e ModB
Se nei 2 moduli volessi chiamare la sub pippo e modificare la textbox pluto
come faccio??????????
In vb6 bastava chiare da una qualsiasi funzione di un modulo
MiaForm.pluto.text = "......" per modificare il testo nel form
e un bel MiaForm.pippo per chiamare la sub.
Ma da .Net non ci riesco.......
Grazie mille

Ci sono vari modi, il piu' OOP e' quello di utilizzare il pattern singleton
ovvero aggiungere al Form una proprieta' la quale ritorna la propria istanza
e usarlo come
Form1.Instance.Text1.Text="abc"
Oppure puoi fare come ha sempre fatto VB6, chiama il tuo Form1 come _Form1
crea una variabile Form1 in un modulo, allo startup del programma associa a
Form1 un istanza di _Form1 e poi usa Form1.Text1.Text="aaa"
Personalmente sceglierei la prima...
-- 
Corrado Cavalli [Microsoft .NET MVP-MCP]
UGIdotNET - 
http://www.ugidotnet.org
Weblog: 
http://www.ugidotnet.org/710.blog

 Form1.Instance.Text1.Text="abc"
Grazie per la risposta ma non capisco come si fa ad associare al form una
proprietà che ritorni
la propria istanza per una textbox.
Mi potresti fare un piccolo esempio.
Io ho il form "Form1" che chiama una sub in un modulo:
    Public Class Form1
        Inherits System.Windows.Forms.Form
    #Region " Codice generato da Progettazione Windows Form "
                 .....................
    #End Region
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
                call Module1.RichiamoSub()
        End Sub
        Public Sub EventoDaChiamare()
                'Altre cose........
        End Sub
    End Class
E nel modulo voglio chiamare la sub "EventoDaChiamare" che è nel form e
modificare una textbox sempre in quel form:
Module Module1
    public sub RichiamoSub()
        call form1.EventoDaChiamare()                        '  MA QUESTO
NON VA.......
        form1.textbox1.text = "Operazione ok"             '  MA QUESTO NON
VA.......
    end sub
End Module
Scusa e grazie

 la propria istanza per una textbox.
[SNIP]
La questione e' stata affrontata parecchie volte, ricapitolando:
In VB6 il nome 'Form1' rappresenta contemporaneamente 2 cose:
- una classe 'Form1' derivata dalla classe base 'Form' (anche se questo
meccanismo di ereditarieta' e' nascosto e non riapplicabile dallo
sviluppatore)
- una variabile oggetto globale 'Form1' di classe 'Form1' che viene
auto-istanziata automaticamente al primo accesso (e che infatti non puo' mai
valere Nothing)
E' possibile ,volendo, creare esplicitamente altre istanze di Form1, ma ogni
qual volta fai riferimento a 'Form1.<qualcosa>' stai effettivamente
accedendo ai membri della istanza predefinita vista sopra.
In 
VB.NET
 diversamente il nome 'Form1' rappresenta soltanto la classe
'Form1' derivata (adesso esplicitamente ) dalla classe base 'Form'
Per poter accedere alle proprieta' di una specifica istanza, quindi, non hai
piu' a disposizione un riferimento globale, ma devi preoccuparti tu stesso
di dichiararlo/passarlo come parametro/aggiungerlo come property a seconda
della situazione.
Per come e' strutturato il tuo caso specifico, hai a disposizione una
soluzione immediata, ovvero semplicemente passare l'istanza di Form1 come
parametro; incidentalmente questa sarebbe stata anche quella piu' corretta e
facilmente riutilizzabile gia' in VB6.
Private Sub Form1_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load
    'Call e' superfluo
    Module1.RichiamoSub(Me)
End Sub
Module Module1
    public sub RichiamoSub(SourceForm As Form1)
        SourceForm.EventoDaChiamare()
        SourceForm.textbox1.text = "Operazione ok"
    end sub
End Module
Ciao
-- 
Luca Dormio - 
luca....@tin.it
________________________________
"Marty, non stai ragionando in maniera quadridimensionale"
Dr. Emmett L. Brown

 Form1.Instance.Text1.Text="abc"
Pattern singleton, per farla semplice, si usa quando c'e'
bisogno di avere una classe con un unica istanza
significativa condivisa da tutti gli oggetti
dell'applicazione (come in VB6 sostanzialmente). E' il
nostro caso quindi :P
Bisogna quindi far si che sia la classe stessa a fornire un
istanza di se stessa (fornendola appunto di una proprieta'
Instance), e *disabilitando* la possibilita' di crearne
altre istanze (in pratica impedendo il metodo New, basta
dichiararlo come Private).
Anche se Corrado la fa semplice, non e' cosi' "banale" :P
nel senso che se aggiungi al form una proprieta' che ritorna
la propria istanza, questo _non basta_ per far funzionare il
tutto, ma ci vogliono un altro paio di accorgimenti.
- Dichiara la Sub New come Private (invece che Public),
impedendo sostanzialmente di creare nuove istanze della
classe, se non all'interno della classe stessa.
- Dichiara un campo (aInstance?) Shared del tipo della
classe (As Form1), ma privato alla classe stessa, nel quale
terrai memorizzata l'istanza attuale della classe.
- Dichiara una proprieta' o un metodo (Instance?) Shared che
restituira' l'istanza corrente (aInstance) se ne esiste una,
altrimenti ne creera' una nuova (e puo' farlo perche' il
metodo New e' privato alla Classe, quindi: aInstance = New
Form1).
Esemplifichiamo:
Public Class Form1
    Inherits System.Windows.Forms.Form
    Private Shared aInstance As Form1
    Shared ReadOnly Property Instance() As Form1
        Get
            If aInstance Is Nothing Then
                aInstance = New Form1()
            End If
            Return aInstance
        End Get
    End Property
'Codice generato da Progettazione Windows Form (apri la
regione :P)
    Private Sub New()
        MyBase.New()
        InitializeComponent()
    End Sub
'Resto del codice generato da Progettazione Windows Form
(lascialo com'e')
    Public Sub MetodoDaRichiamare()
        Call MessageBox.Show("Metodo chiamato!")
    End Sub
'Tutti gli altri Metodi/Proprieta' che vuoi
End Class
A questo punto da Module1 o da qualunque altro punto
dell'applicazione potrai richiamare il tuo Form1 "quasi"
come facevi in VB, nel senso che il form al quale ti devi
riferire e' "Form1.Instance" e non "Form1".
Public Module Module1
    Public Sub TestModule()
        Call Form1.Instance.MetodoDaRichiamare()
    End Sub
End Module
Et voila' il gioco e' fatto.
hth,
Lokar
-- 
Sito Comune: 
http://www.it-lang-vb.net/
Manifesto: 
http://www.it-lang-vb.net/docs/Manifesto.txt
Statuto: 
http://www.it-lang-vb.net/docs/Statuto.txt
UGIdotNET - 
http://www.ugidotnet.org

 dichiararlo come Private).
[SNIP]
Al di la' delle giuste precisazioni, bisogna considerare pero' che questo
metodo "serio" ha una forte limitazione, cioe' appunto quella di non poter
piu' usare istanze multiple della stessa form, cosa che in molte
applicazioni reali e' spesso indispensabile (quelle MDI sono un caso tipico
ma non solo)
Questo potrebbe anche essere accettabile nel caso specifico, ma dato che il
problema di Gabuz pare solo quello di fare riferimento nella routine
all'istanza corretta di form, rimango dell'idea che la soluzione piu'
adatta, tutto sommato, sia semplicemente quella di parametrizzare la
funzione come dicevo prima; e' sufficientemente OO ed evita nel contempo la
"pecionata" della variabile Form globale ;-)


 ed evita nel contempo la "pecionata" della variabile Form globale ;-)
Le mie sono solo precisazioni su quanto detto da Corrado che io stesso ho gran
difficolta' a seguire a volte :P (Peace and Love Corrado ;) ). Probabilmente
per progetti di "piccolo calibro" utilizzerei il tuo approccio, ma l'approccio
cosiddetto "pattern singleton" coverrai che ricalca senz'altro meglio
l'approccio ai form di VB6. Inoltre questo tipo di pattern viene utilizzato
prevalentemente per il/i form principale/i di un applicazione a finestre.
Un'ultimo appunto (chiedo venia se sono prolisso). Il pattern singleton e'
egualmente applicabile a qualunque tipo di classe, non necessariamente ad
un form ovvero in quei casi in cui si voglia avere un'unica istanza di
una classe condivisa da tutti gli oggetti dell'applicazione.
Just my 2 eurocent,


Questa sera proverò tutti i vari aiuti che mi avete dato e vi
farò sapere.
Grazie mille della disponibilità.
Ciao

 di VB6.
l'approccio di VB6 e': "ti offro una classe tradizionale, poi, per la tua
comodita' ti definisco una istanza gia' pronta; se ti va bene usi sempre
quella, se no in qualsiasi momento istanzia quelle che vuoi" che per
l'appunto e' piu' vicino a quello visto poco piu' sopra che non al singleton
vero e proprio.
Il nocciolo della faccenda pero' e' che Gabuz ha bisogno che la routine
lavori sulla stessa istanza di form che l'ha invocata, e poco c'entra se
parliamo di progetti piccoli o grossi; non e' tanto importante che sia un
istanza unica per tutto il progetto o istanze multiple, purche' ogni volta
sia *quella*... ora, con la proprieta' shared 'Instance' definita come prima
hai comunque il problema:
- se e' un singleton "vero" funziona, ma non potrai mai avere due istanze di
Form1.
- se e' un singleton "misto" (perdona il termine) funziona, ma solo se ti
curi di utilizzare sempre e solo l'istanza 'Instance' ogni qual volta ti
serve la routine.
Per capirci meglio, questo tipo di chiamata non funziona:
Dim f As Form1 = New Form1
Form1.Show
Private Sub Form1_Load(....)
    Module1.RichiamoSub()
End Sub
Public Module Module1
    Public Sub TestModule()
        Call Form1.Instance.MetodoDaRichiamare()
    End Sub
End Module
perche', a seconda di come hai definito il costruttore di Form1 e il metodo
Instance, o non puoi eseguire l'istruzione 'New Form1', oppure la routine
TestModule lavora sull'istanza sbagliata, perche' non e' quella chiamante.
Aggiungendo il parametro al medoto invece hai una soluzione pulita che
funziona per tutte le modalita' (singleton, istanze multiple, istanza
globale) e per progetti di tutte le dimensioni.


Grazie a tutti per le risposte.
Credo che per ora passerò l'istanza della form al modulo.
L'unica cosa è che potrei avere più form da gestire e questo vuol dire che
in una eventuale classe che deve richiamare due form distinte dovrei crearmi
delle apposite sub per il passaggio di tutte le form..........
Questo almeno è quello che ho capito se voglio adottare questo metodo....o
no?
Ciao


Non necessariamente
se le diverse form che vuoi gestire devono avere, o sono riconducibili, a
caratteristiche comuni (per esempio espongono tutte un metodo
'EventoDaChiamare' e hanno un TextBox1(*) da aggiornare, come nel tuo
esempio) allora puoi facilmente utilizzare una sola routine generalizzata
che sfrutti il polimorfismo, ovvero l'uso di interfacce.
Definendone una opportuna e implementandola in tutte le form che ti
interessano, potrai utilizzarla come parametro della funzione esterna e
riutillizzarla ad libitum.
Cerca sulla guida o sul tuo libro di fiducia l'argomento; una volta compresa
la teoria, l'applicazione pratica e' molto semplice.
(*) gia' che ci siamo, il sistema migliore per avere codice piu' facillmente
riutilizzabile, e' quello di evitare da routine esterne di fare riferimento
direttamente ai controlli delle form; quindi, cosi' come hai definito un
metodo pubblico EventoDaChiamare, allo stesso modo puoi definire un metodo o
una property TestoDaAggiornare(Testo)... sara' il codice interno che
scriverai nella form a preoccuparsi di scrivere il valore nel controllo
giusto.
Questo per inciso facilita ulteriormente la soluzione vista sopra.


 Luca Dormio - 
luca....@tin.it
-- 
.A
UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org
Read my blog at: 
http://www.ugidotnet.org/4.blog