C # Multi Threading - Objekte zwischen Threads verschieben

9

Ich arbeite mit einem winforms-Steuerelement, das sowohl ein GUI-Element als auch eine interne Verarbeitung ist, die dem Entwickler nicht zur Verfügung gestellt wurde. Wenn diese Komponente instanziiert wird, kann es zwischen 5 und 15 Sekunden dauern, um fertig zu sein, also was ich tun möchte, ist es auf einen anderen Thread zu setzen und wenn es fertig ist, bringe es zurück zum Gui-Thread und lege es auf mein Formular. Das Problem ist, dass dies eine Kreuzthread-Ausnahme verursacht (und hat).

Normalerweise, wenn ich mit Worker-Threads arbeite, kann ich nur mit einfachen Datenobjekten zurückfahren, wenn die Verarbeitung abgeschlossen ist, und dann mit Steuerelementen im Hauptthread verwenden, aber nie ein ganzes Steuerelement auf diese Weise verschieben müssen.

>

Weiß jemand, ob das möglich ist und wenn ja wie? Wenn nicht, wie geht man mit einem Problem wie diesem um, wo es die Möglichkeit gibt, das Hauptgui zu sperren?

    
Grant 01.06.2010, 23:36
quelle

4 Antworten

3

Sie müssen die GUI nicht sperren, Sie müssen nur invoke aufrufen:

  

Steuerelemente in Windows Forms sind gebunden   ein bestimmter Thread und kein Thread   sicher. Wenn Sie also einen Anruf tätigen   Kontrollmethode von einem anderen   Thread, müssen Sie einen der verwenden   controls ruft Methoden zum Marshalen auf   der Aufruf an den richtigen Thread. Dies   Eigenschaft kann verwendet werden, um zu bestimmen, ob   Sie müssen eine Aufrufmethode aufrufen, die   kann nützlich sein, wenn Sie nicht wissen, was   Thread besitzt ein Steuerelement. ref

So sieht es im Code aus:

%Vor%

Das Aufrufen von LoadComponent aus einem anderen Thread führt normalerweise zu einer Thread-übergreifenden Ausnahme, aber bei der obigen Implementierung wird die Methode im GUI-Thread aufgerufen.

InvokeRequired sagt Ihnen, wenn:

  

Der Aufrufer muss eine Aufrufmethode aufrufen   wenn Sie Methodenaufrufe an die   Kontrolle, weil der Anrufer auf a ist   anderer Thread als der eine   Kontrolle wurde am erstellt.    ref

Aktualisierung:
Wenn ich Sie also richtig verstehe, wird das Steuerelementobjekt auf einem anderen Thread als dem GUI-Thread erstellt. Daher können Sie es auch dann nicht verwenden, wenn Sie es an den GUI-Thread übergeben konnten, ohne eine Thread-übergreifende Ausnahme zu verursachen . Die Lösung wäre, das Objekt im GUI-Thread zu erstellen, aber in einem separaten Thread zu initialisieren:

%Vor%     
Kiril 01.06.2010 23:40
quelle
1

Ohne zu viel über das Objekt zu wissen. Um Kreuzthread-Ausnahmen zu vermeiden, können Sie den ersten Thread veranlassen, einen Aufruf aufzurufen (auch wenn Sie von einem Thread aus aufrufen).

Von einer meiner eigenen Anwendungen kopiert und eingefügt:

%Vor%

Im Wesentlichen ruft die Thread-Task die "Async" -Methode auf. Welches wird dann das Hauptformular zu starten nennen (eigentlich Async selbst).

Ich glaube, dass es wahrscheinlich einen kürzeren Weg gibt, all dies zu tun, ohne dass Delegierte und zwei verschiedene Methoden geschaffen werden müssen. Aber dieser Weg ist einfach in mir verwurzelt. Und es ist, was die Microsoft-Bücher Ihnen beibringen: p

    
MindingData 01.06.2010 23:41
quelle
0

Die Klasse BackgroundWorker wurde für genau diese Situation entwickelt. Es wird den Thread für Sie verwalten und Sie können den Thread starten sowie den Thread abbrechen. Der Thread kann Ereignisse für Statusaktualisierungen oder Abschluss an den GUI-Thread zurücksenden. Die Ereignishandler für diese Status- und Beendigungsereignisse befinden sich im Hauptthread der Benutzeroberfläche und können Ihre WinForm-Steuerelemente aktualisieren. Und das WinForm wird nicht gesperrt. Es ist alles, was Sie brauchen. (Und funktioniert genauso gut in WPF und Silverlight.)

    
Cylon Cat 02.06.2010 03:20
quelle
0

Das Steuerelement muss über den UI-Thread erstellt und geändert werden.

Um die Benutzeroberfläche während einer lang laufenden Initialisierung ansprechend zu halten, behalten Sie den Prozess in einem Hintergrundthread und rufen Sie alle Steuerzugriffe auf. Die Benutzeroberfläche sollte reaktionsfähig bleiben. Wenn dies nicht der Fall ist, können Sie dem Hintergrundthread etwas Wartezeit hinzufügen. Dies ist ein Beispiel mit .Net 4 parallelen Tools: Ссылка

Wenn die Interaktion mit dem spezifischen Steuerelement, das initialisiert werden soll, nicht erlaubt werden darf, bis die Initialisierung beendet ist, dann verstecke oder deaktiviere es, bis es abgeschlossen ist.

    
Ragoczy 03.06.2010 13:12
quelle

Tags und Links