Modificare gli elementi di un form da un thread
Categories: C, Source Code
Tags:
Scenario:
Si vuole eseguire al clic di un certo elemento di un Form un’operazione abbastanza lunga, come per esempio lo scaricamento di alcuni files da internet, ma durante l’operazione l’utente deve poter avere il controllo del programma e avere un feedback visivo della percentuale di completamento dell’operazione.
Soluzione non funzionante:
Ci si rende conto subito che per risolvere un problema del genere è necessario utilizzare un Thread che esegua l’operazione in un contesto separato da quello del Form principale, altrimenti il programma si bloccherà in attesa della fine dell’operazione senza possibilità di ricevere input dall’utente. Il vero problema adesso si crea quando si cerca di aggiornare i componenti del Form dal Thread:
private void button1_Click(object sender, EventArgs e)
{
testThread = new Thread(threadProc);
testThread.Start();
}
public void threadProc()
{
// wast a lot of time...
for (int i = 1; i <= 10; i++)
{
Thread.Sleep(250);
progressBar.Value = i * 10;
}
MessageBox.Show("Operation Completed!");
}
Purtroppo, all’esecuzione della riga di codice dove viene assegnato il valore alla progressBar si otterrà un messaggio di errore simile al seguente:
“Operazione cross-thread non valida: è stato eseguito l’accesso al controllo ‘progressBar1′ da un thread diverso da quello da cui è stata eseguita la creazione.”

Soluzione funzionante
Per far sì che un thread esterno possa accedere agli elementi nel form bisogna invece creare un delegate inserendogli come parametri le informazioni che vogliamo cambiare nel form dal thread, in questo caso per esempio la percentuale di completamento:
public delegate void SetProgressBarDelegate(int value);
Poi scrivere il metodo SetProgressBar da assegnare al delegate:
public void SetProgressBar(int value)
{
lock (this)
{
progressBar1.Value = value;
}
}
Il lock serve per assicurarsi che il form non sia utilizzato da nessun altro processo (in pratica è come se il codice tra graffe venisse circondato da Monitor.Enter e Monitor.Exit), e ne blocca l’utilizzo da altri thread durante l’esecuzione del codice tra graffe: in questo modo possiamo operare sugli oggetti del form senza correre nessun rischio.
Infine all’interno del thread invochiamo il metodo SetProgressBar:
public void threadProc()
{
for (int i = 1; i <= 10; i++)
{
Thread.Sleep(250);
this.progressBar1.Invoke(
new SetProgressBarDelegate(this.SetProgressBar), i * 10);
}
MessageBox.Show("Operation Completed!");
}
In questo modo il programma funzionerà correttamente e il thread riuscirà a modificare l’elemento del form senza causare nessuna operazione cross-thread non valida.
Download Form-Thread Interaction. Downloads: 211
Nel download, l’esempio appena descritto in un progetto Visual Studio 2005.
Se sei interessato a questo post, potresti anche provare a leggere:
-
No related posts
19 Giu 2007 dzamir
Io ho un problema ho un servizio windows che riceve messaggi su un socket tcp…
e su un altro thread un server telnet …. devo far si che venga notificato in tempo reale sul client telnet i messaggi ricevuti dal servizio
Sai mica come potrei risolvere questo problema?
Adesso non ti posso aiutare perché dove mi trovo adesso non ho il Visual Studio installato! Domani ci provo e ti faccio sapere!
…grazie…
Allora… io e Andrea (l’altro admin del blog) abbiamo avuto un problema simile in ufficio quando abbiamo programmato un server che riceveva messaggi da diverse connessioni TCP e UDP. Un Thread doveva leggere tutti i messaggi che arrivavano dalle diverse connessioni, che ovviamente erano su Thread diversi.
Per risolvere abbiamo creato una classe che abbiamo chiamato MessageQueue. Questa classe ha all’interno una coda di messaggi (un oggetto Queue), un metodo per aggiungere messaggi alla coda e un altro metodo per leggere i messaggi dalla coda. Questi metodi sono programmati Thread-Safe, ovvero utilizzando Monitor.Enter() e Monitor.Exit() dove è necessario. Così facendo i Thread delle connessioni possono aggiungere messaggi alla coda quando serve, e il Thread che deve controllare tutti i messaggi ricevuti ogni tot millisecondi chiama il metodo per leggere i messaggi e controlla se ci sono messaggi da leggere nella coda.
Davide ti amo tanto!
ATTENZIONE!!!!
FACCIAMO MICA USO PERSONALE DI UN “PUBBLICO SERVIZIO”??!!!
EHM…SI!!
ANDRE, TI AMO TANTO, TANTO TANTO!
Siete due fidanzate spammerone!!
prrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr!!!!
Dà, ma quella famosa mail t’è più arrivata?