ich habe innerhalb einer WindowsForm ein Codestück, das ich schon sehr oft verwendet habe, und das nun erstmals Probleme bereitet. Den Code werden die meisten kennen:
delegate void SetStatusTextCallback(string sText); public void SetStatusText(string sText) { if (InvokeRequired) { SetStatusTextCallback d = new SetStatusTextCallback(SetStatusText); Invoke(d, new object[] { sText }); // **** hier bleibt das Programm hängen } else { lbStatus.Text = sText; } }
Der Code funktioniert mehrmals ohne Probleme, so lange der Invoke nicht notwendig ist. Beim 4. Aufruf wird der Invoke dann notwendig, und die Methode bleibt in der markierten Zeile hängen. Wenn ich einen Breakpoint an den Anfang der Methode setze, sehe ich, dass beim Invoke die Methode SetStatusText nicht aufgerufen wird. Wenn ich Invoke und InvokeRequired auf lbStatus aufrufe, passiert das gleiche. Hat jemand eine Idee, was da passiert?
Könnte es ein Deadlock sein? Etwa so: der UI-Thread wartet auf einen Background-Thread, dieser ruft SetStatusText, läuft in den InvokeRequired-Zweig, der kommt aber nicht weiter, weil der UI-Thread ja noch blockiert ist...
Auf welcher Ebene befindet sich eigentlich Deine Methode? Wenn Du das so in den Code der Form eingebaut hast wird this angenommen. Du möchtest aber eine Textbox aktualisieren, also musst Du der Methode das Element mitgeben. Etwa so
Sowohl this.InvokeRequired (this = Form), als auch itm.InvokeRequired gehen auf den gleichen UI-Thread, das sollte also egal sein. Man kann es auch so machen wie du schreibst, insbesondere, wenn man bei verschiedenen Textboxen den Text updaten will, ist das praktischer. Man kann auch allgemein das Control übergeben (System.Windows.Forms.Control), dann kann man bei verschiedenen Controls (Textboxen, Labels etc) das Text-Attribut ändern. Man könnte sogar den Attributnamen (Hier: "Text") als string übergeben und dann per Reflection nicht nur den Text, sondern ein beliebiges Attribut ändern.
Da hast Du natürlich Recht. Allerdings hat dieses Konstrukt bei mir bisher immer wie erwartet funktioniert. Aber Du hast das jetzt ja mit BeginInvoke hinbekommen....
Bei mir hatte der angegebene Code bisher ja auch immer funktioniert. Und ich hatte es in meinem Code auch schon mit dem Aufruf von Invoke und InvokeRequired auf dem Control versucht, und es hatte nicht funktioniert, eben weil ich ein Deadlock hatte. Es war einfach ein anderes Problem. Deine Methode ist aber sicherer, falls Micosoft irgendwann seine Architektur ändert.