|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Member
Iscritto dal: Aug 2007
Messaggi: 138
|
[WIN FORM .NET] Eseguire operazioni sul form mentre è in corso una routine
Ho un windows form che al click di un pulsante esegue un'operazione un pò lunga. Nel form c'è anche una label che durante la routine vorrei che assumesse valori diversi. Ho provato ad impostare il testo della label ma non viene visualizzato fin quando la routine non finisce di lavorare. C'è un modo per far eseguire il rendering della label mentre la routine sta girando?
|
![]() |
![]() |
![]() |
#2 |
Senior Member
Iscritto dal: Oct 2005
Messaggi: 1044
|
la tua routine la devi far eseguire su un thread diverso, se no è normale che la gui rimanga bloccata.
Il modo più semplice di fare questo secondo me è utilizzare la classe BackgroundWorker. Il tutorial è molto chiaro, se comunque hai problemi non esitare a chiedere |
![]() |
![]() |
![]() |
#3 | |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Quote:
![]() |
|
![]() |
![]() |
![]() |
#4 |
Senior Member
Iscritto dal: Jun 2007
Città: Milano
Messaggi: 413
|
Non sono tanto d'accordo con l'uso del metodo DoEvents.
E' sicuramente vero che in modo semplice riesci a fare quello che ti serve, ovvero aggiornare la label, ma il form rimane comunque bloccato nel tempo che intercorre tra le due chiamate al metodo DoEvents. Inoltre può essere utile, mentre è in corso questa elaborazione un po' lunga, che l'utente possa fare altre operazioni con il programma, cosa che non è fattibile se l'elaborazione è fatta nel thread della gui. L'uso di BackgroundWorker o comunque di thread specifici per ogni computazione lunga è sicuramente una scelta un po' più complicata da realizzare ma che sicuramente paga in termini di usabilità, versatilità e performances. |
![]() |
![]() |
![]() |
#5 | |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Quote:
Inoltre non è affatto vero, come dici, che l'interazione con la gui non sia fattibile dallo stesso thread. Basta verificare se c'è stata interazione dell'utente con GetInputState : http://www.dotnet2themax.it/ShowCont...3-48e19d3cf6a5 Che poi, in casi più complessi il multithread sia praticamente d'obbligo è un altro discorso, ma per il refresh di una Label mi sembra uno spreco. |
|
![]() |
![]() |
![]() |
#6 | |
Senior Member
Iscritto dal: Jun 2007
Città: Milano
Messaggi: 413
|
Quote:
Comunque la domanda l'avevo letta bene, e non discuto che con il metodo DoEvents possa funzionare, ritengo solo che sia una soluzione veloce ma che vale ben poco. |
|
![]() |
![]() |
![]() |
#7 | |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Quote:
Non penso fosse l'intenzione di voyager18. Potrei sbagliarmi, ma credo si tratti di una sua routine ciclica, da qui la mia risposta. In ogni caso finchè voyager18 non si fa vivo con info più precise, resto dell'idea che DoEvents sia da preferirsi nei casi molto semplici, come penso sia questo. |
|
![]() |
![]() |
![]() |
#8 |
Senior Member
Iscritto dal: Jul 2002
Città: Reggio Calabria -> London
Messaggi: 12093
|
Io sono assolutamente contrario a bloccare il thread della GUI.
Non c'è niente di peggio che possa essere fatto. In questo modo viene bloccata anche tutta la gestione degli eventi, e il programma si comporta come se fosse in hang, inoltre non credo sia affatto scontato che il rendering della label venga effettuato correttamente, o meglio, quantomeno con java era scritto *esplicitamente* questo, ma ad occhio direi che possa valere anche per le winforms. Quantomeno, in caso non si voglia usare un backgroundworker, sarebbe opportuno utilizzare dei delegate con BeginInvoke per mandare in background l'esecuzione del metodo bloccante.
__________________
![]() |
![]() |
![]() |
![]() |
#9 | ||
Senior Member
Iscritto dal: Jun 2007
Città: Milano
Messaggi: 413
|
Quote:
Quote:
Detto questo, io non volevo sindacare sull'istruzione, conosco bene quello che fa, ma ritengo che vada usata il meno possibile per questo genere di cose perchè potrebbe portare a spiacevoli risultati. |
||
![]() |
![]() |
![]() |
#10 |
Senior Member
Iscritto dal: Oct 2005
Messaggi: 1044
|
condivido le risposte degli utenti ^TiGeRShArK^ e CwNd per questo avevo fin da subito proposto il backgroundworker
![]() |
![]() |
![]() |
![]() |
#11 | |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Quote:
"Anche con il DoEvents" non c'entra un fico. Ovvio che se fai il download con singola istruzione non lo usi, il DoEvents, perchè non sai manco dove metterlo, che razza di discorso è ?! E nemmeno col tuo multithread riesci a cavare un ragno da un buco in quel caso. Prova a mettere la percentuale del file scaricato in una Label con My.Computer.Network.DownloadFile(), con o senza multithread, e fammi sapere. 2. La tecnica che ho linkato più sopra è valida. L'ho usata personalmente, funziona, e la consiglio. Poi starà a chi ha domandato farne l'uso che crede. Secondo me chi ha aperto il thread ha il classico problema di routine ciclica ( poi... mi sbaglierò... ). Ad ogni ciclo vorrebbe vedere la Label aggiornarsi ecc... ecc... Punto. Se è davvero tutto qui e non c'è altro, il mio consiglio è : DoEvents. 3. La soluzione targata F. Balena ( che comunque qui è superflua e l'ho tirata in ballo solo per dimostrare che si può fare eccome ciò che sostieni fosse impossibile ) per me è il miglior compromesso tra facilità di implementazione e funzionalità nei casi semplici, ripeto. C'è chi dice "MAI DoEvents, solo multithread". Opinioni. Secondo me ci sono casi e casi... Con tutto il rispetto che ho per voi, preferisco dare credito al consiglio di un Balena, che peraltro ho avuto modo di verificare in concreto, anche se in contrasto con quello di 10 di voi messi assieme. |
|
![]() |
![]() |
![]() |
#12 | ||
Senior Member
Iscritto dal: Jun 2007
Città: Milano
Messaggi: 413
|
Quote:
Quote:
|
||
![]() |
![]() |
![]() |
#13 | |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Quote:
Personalmente ho usato parecchio il threading in .Net, e convengo che in generale sia da preferirsi. Ma non è la soluzione più veloce. E io voglio che l'utente che ha posto la domanda sappia che esiste anche la soluzione "veloce", che nelle cose semplici è valida e funzionante. Che ci volete fare, ho la testa dura. ![]() Ho una Form con un solo pulsante che esegue questo codice : Codice:
For i As Integer = 1 To 10000 Label1.Text = i Next E di casi simili a questo, certo ben più significativi, ne ho visti a centinaia. Che faccio, consiglio il multithreading + relativa gestione del cross-thread sulla Form, come prima cosa ? Tu dirai : SI. Io invece dico : vediamo se è davvero una cosa veloce, al threading si fa sempre a tempo, semmai. Quindi è QUI l'opinione, semmai, NON sul fatto che il multithreading sia o meno la scelta più corretta. Codice:
For i As Integer = 1 To 10000 Label1.Text = i My.Application.DoEvents() Next Più performante o meno, dato che poi comunque sta benedetta Label la devi aggiornare dall'altro Thread ? Forse un pochino... Comunque sia questa è la soluzione in assoluto più semplice, adatta ai casi semplici. Cosa volete che vi dica : se DoEvents non vi piace, fate una petizione al Team di VS perchè venga deprecato. ![]() |
|
![]() |
![]() |
![]() |
#14 | |
Member
Iscritto dal: Aug 2007
Messaggi: 138
|
Quote:
|
|
![]() |
![]() |
![]() |
#15 |
Senior Member
Iscritto dal: Jun 2007
Città: Milano
Messaggi: 413
|
Prova a fare una semplice
Codice:
Thread.Sleep(3000) La tua label sicuramente verrà aggiornata, ma la gui non risponderà agli eventi. Nel caso possono essere così lunghe ti suggerisco di usare i metodi asincroni per fare le chiamate. Se hai generato il proxy per il webservice tramite svcutils.exe c'è un opzione per far generare le classi direttamente con qui metodi. Da visual studio basta che quando fai "aggiungi riferimento al servizio" vai su "avanzate" e spunti la casella "Genera operazioni asincrone". Usandoli sicuramente non hai problemi di freezing della gui e potrai farci qualsiasi operazione. Ultima modifica di CwNd : 28-12-2009 alle 18:38. |
![]() |
![]() |
![]() |
#16 | |
Senior Member
Iscritto dal: Jul 2002
Città: Reggio Calabria -> London
Messaggi: 12093
|
Quote:
Praticamente ad ogni istruzione resterà bloccato tutto aggiornandosi solo quando verrà chiamata l'Application.DoEvents() tra un'istruzione e l'altra. La soluzione + completa per me è il backgroundworker, ma volendo anche il begininvoke col callback può andare bene, dipende dalle situazioni...
__________________
![]() |
|
![]() |
![]() |
![]() |
#17 | |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Quote:
![]() E la Label quando la vuoi refreshare ? E magari postare un po' di codice ? Però mi raccomando, sempre informazioni col contagocce, sennò è troppo facile. ![]() |
|
![]() |
![]() |
![]() |
#18 | |
Senior Member
Iscritto dal: Jul 2002
Città: Reggio Calabria -> London
Messaggi: 12093
|
Quote:
![]() in effetti... ![]()
__________________
![]() |
|
![]() |
![]() |
![]() |
#19 |
Member
Iscritto dal: Aug 2007
Messaggi: 138
|
Ho provato con il background worker e funziona! Grazie a tutti!!
![]() |
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 07:05.