.NET Framework
threading
Ricerca…
Accesso ai controlli del modulo da altri thread
Se si desidera modificare un attributo di un controllo come una casella di testo o un'etichetta da un altro thread rispetto al thread della GUI che ha creato il controllo, sarà necessario richiamarlo altrimenti si potrebbe ottenere un messaggio di errore che indica:
"Operazione cross-thread non valida: controllo 'control_name' accessibile da un thread diverso dal thread su cui è stato creato."
L'uso di questo codice di esempio su un modulo system.windows.forms genera un'eccezione con quel messaggio:
private void button4_Click(object sender, EventArgs e)
{
Thread thread = new Thread(updatetextbox);
thread.Start();
}
private void updatetextbox()
{
textBox1.Text = "updated"; // Throws exception
}
Invece quando si desidera modificare il testo di una casella di testo all'interno di un thread che non lo possiede, utilizzare Control.Invoke o Control.BeginInvoke. È inoltre possibile utilizzare Control.InvokeRequired per verificare se è necessario il richiamo del controllo.
private void updatetextbox()
{
if (textBox1.InvokeRequired)
textBox1.BeginInvoke((Action)(() => textBox1.Text = "updated"));
else
textBox1.Text = "updated";
}
Se è necessario farlo spesso, è possibile scrivere un'estensione per oggetti richiamabili per ridurre la quantità di codice necessaria per effettuare questo controllo:
public static class Extensions
{
public static void BeginInvokeIfRequired(this ISynchronizeInvoke obj, Action action)
{
if (obj.InvokeRequired)
obj.BeginInvoke(action, new object[0]);
else
action();
}
}
E l'aggiornamento della casella di testo da qualsiasi thread diventa un po 'più semplice:
private void updatetextbox()
{
textBox1.BeginInvokeIfRequired(() => textBox1.Text = "updated");
}
Tenere presente che Control.BeginInvoke come in questo esempio è asincrono, il che significa che il codice proveniente dopo una chiamata a Control.BeginInvoke può essere eseguito immediatamente dopo, indipendentemente dal fatto che il delegato passato sia stato eseguito o meno.
Se devi essere sicuro che textBox1 sia aggiornato prima di continuare, usa invece Control.Invoke, che bloccherà il thread chiamante fino a quando il tuo delegato non sarà stato eseguito. Si noti che questo approccio può rallentare notevolmente il codice se si effettuano molte chiamate invocate e si noti che l'applicazione si bloccherà se il thread della GUI è in attesa che il thread chiamante completi o rilasci una risorsa trattenuta.