.NET Framework
Einfädeln
Suche…
Zugriff auf Formularsteuerelemente von anderen Threads
Wenn Sie ein Attribut eines Steuerelements (z. B. ein Textfeld oder eine Beschriftung) aus einem anderen Thread als dem GUI-Thread, mit dem das Steuerelement erstellt wurde, ändern möchten, müssen Sie es aufrufen. Andernfalls erhalten Sie möglicherweise eine Fehlermeldung, die Folgendes angibt:
"Cross-Thread-Vorgang nicht gültig: Auf Steuerelement 'Steuerelementname' wurde von einem anderen Thread als dem Thread zugegriffen, in dem er erstellt wurde."
Die Verwendung dieses Beispielcodes in einem system.windows.forms-Formular führt zu einer Ausnahme mit dieser Nachricht:
private void button4_Click(object sender, EventArgs e)
{
Thread thread = new Thread(updatetextbox);
thread.Start();
}
private void updatetextbox()
{
textBox1.Text = "updated"; // Throws exception
}
Wenn Sie den Text eines Textfelds innerhalb eines Threads ändern möchten, der nicht Eigentümer ist, verwenden Sie Control.Invoke oder Control.BeginInvoke. Sie können auch Control.InvokeRequired verwenden, um zu prüfen, ob das Aufrufen des Steuerelements erforderlich ist.
private void updatetextbox()
{
if (textBox1.InvokeRequired)
textBox1.BeginInvoke((Action)(() => textBox1.Text = "updated"));
else
textBox1.Text = "updated";
}
Wenn Sie dies häufig tun müssen, können Sie eine Erweiterung für aufrufbare Objekte schreiben, um den für diese Prüfung erforderlichen Code zu reduzieren:
public static class Extensions
{
public static void BeginInvokeIfRequired(this ISynchronizeInvoke obj, Action action)
{
if (obj.InvokeRequired)
obj.BeginInvoke(action, new object[0]);
else
action();
}
}
Das Aktualisieren des Textfelds von einem beliebigen Thread wird ein bisschen einfacher:
private void updatetextbox()
{
textBox1.BeginInvokeIfRequired(() => textBox1.Text = "updated");
}
Beachten Sie, dass Control.BeginInvoke, wie in diesem Beispiel verwendet, asynchron ist. Dies bedeutet, dass Code, der nach einem Aufruf von Control.BeginInvoke kommt, sofort ausgeführt werden kann, nachdem der übergebene Delegat bereits ausgeführt wurde.
Wenn Sie sicherstellen möchten, dass textBox1 aktualisiert wird, bevor Sie fortfahren, verwenden Sie stattdessen Control.Invoke. Dadurch wird der aufrufende Thread so lange blockiert, bis Ihr Delegat ausgeführt wurde. Beachten Sie, dass dieser Ansatz Ihren Code erheblich verlangsamen kann, wenn Sie viele Aufrufe aufrufen und beachten, dass Ihre Anwendung dadurch blockiert wird, wenn Ihr GUI-Thread darauf wartet, dass der aufrufende Thread eine angehaltene Ressource beendet oder freigibt.