Wie kann ich auf den UI-Thread Ausbeute die Benutzeroberfläche zu aktualisieren, während App tut Batch-Verarbeitung in einem WinForm?

StackOverflow https://stackoverflow.com/questions/106036

  •  01-07-2019
  •  | 
  •  

Frage

Ich habe eine WinForms-Anwendung in C # geschrieben mit .NET 3.5. Es läuft ein langwieriger Batch-Prozess. Ich möchte die App aktualisieren Status, was der Batch-Prozess tut. Was ist der beste Weg, um die Benutzeroberfläche zu aktualisieren?

War es hilfreich?

Lösung

Die Background klingt wie das Objekt, das Sie wollen.

Andere Tipps

Die schnelle und schmutzige Art und Weise verwendet Application.DoEvents() Aber dies kann Probleme bei der Bestellung Ereignissen verursacht, werden behandelt. So ist es nicht zu empfehlen

Das Problem ist wahrscheinlich nicht, dass Sie auf den UI-Thread zu erhalten, aber, dass Sie die Verarbeitung auf dem UI-Thread tun blockiert es von Nachrichten Handhabung. Sie können die Background Komponente verwenden, um die Stapelverarbeitung auf einem anderen Thread zu tun, ohne den UI-Thread blockiert wird.

Führen Sie den langwierigen Prozess auf einem Hintergrund-Thread. Der Hintergrund Arbeiter-Klasse ist eine einfache Möglichkeit, dies zu tun - es ist für das Senden von Fortschritt Updates und Abschluss Ereignisse, für die die Ereignishandler aufgerufen werden auf dem richtigen Thread für Sie einfache Unterstützung zur Verfügung stellt. Dies hält den Code sauber und präzise.

die Updates anzuzeigen, Fortschrittsbalken oder Statusleiste Text sind zwei der am häufigsten verwendeten Ansätze.

Der Schlüssel ist daran zu denken ist, wenn man die Dinge auf einem Hintergrund-Thread tun, Sie auf den UI-Thread, um umschalten etc Windows-Steuerelemente zu aktualisieren.

Um Rindfleisch, was die Leute über DoEvents sagen, hier ist eine Beschreibung dessen, was passieren kann.

Angenommen, Sie in irgendeiner Form mit Daten über sie und Ihre lange Laufereignis wird in die Datenbank zu speichern oder einen Bericht über die zugrunde zu erzeugen. Sie beginnen zu speichern oder den Bericht zu erzeugen, und dann wird Sie über DoEvents aufrufen, so dass der Bildschirm Malerei hält.

Leider ist der Bildschirm nicht nur Malerei, wird es auch auf Benutzeraktionen reagieren. Dies liegt daran, DoEvents stoppt, was Sie tun jetzt alle Fenster Nachrichten zu verarbeiten wartet darauf, von Ihrem WinForms App verarbeitet zu werden. Diese Nachrichten enthalten Anfragen neu zu zeichnen, sowie alle Benutzer Typisierung, Klicken, etc.

So zum Beispiel, während Sie die Daten sind zu speichern, kann der Anwender Dinge wie machen die App ein modales Dialogfeld anzuzeigen, die auf die lange Lauf Aufgabe völlig unabhängig ist (zB Hilfe-> Über). Jetzt sind Reagieren Sie auf neue Benutzeraktionen innerhalb die bereits laufenden lange laufende Aufgabe. DoEvents zurückkehren wird, wenn alle Ereignisse, die darauf warten, wenn Sie es fertig genannt werden, und dann lange laufende Aufgabe wird fortgesetzt.

Was passiert, wenn der Benutzer nicht schließt den modalen Dialog? Ihre lange laufende Aufgabe wartet immer, bis dieser Dialog geschlossen wird. Wenn Sie mit einer Datenbank sind zu begehen und eine Transaktion zu halten, jetzt sind halten Sie eine Transaktion offen, während der Benutzer einen Kaffee mit. Entweder Ihre Transaktionszeiten und Sie verlieren Ihre Ausdauer Arbeit, oder die Transaktion nicht Timeout und Sie möglicherweise Deadlock andere Benutzer des DB.

Was hier passiert, ist, dass Application.DoEvents Code einspringenden macht. Sehen Sie sich die Wikipedia-Definition hier . Beachten Sie einige Punkte von der Spitze des Artikels, dass für die Code-Reentry zu sein, es:

  • Müssen keine statische (oder global) nicht konstante Daten halten.
  • darf nur auf den Daten, die ihm von dem Anrufer bereitgestellt arbeiten.
  • darf nicht auf Sperren verlassen Ressourcen Singletons.
  • darf nicht nennen nichtablaufinvarianten Computerprogramme oder Routinen.

Es ist sehr unwahrscheinlich, dass langer Lauf Code in einer WinForms-Anwendung arbeitet nur auf Daten auf das Verfahren durch den Aufrufer übergeben, nicht gilt statische Daten, hält keine Schlösser und fordert nur andere einspringende Methoden.

Wie viele Menschen hier sagen, DoEvents einige sehr seltsame Szenarien im Code führen kann. Die Fehler es kann dazu führen, kann sehr schwer zu diagnostizieren, und Ihre Benutzer ist nicht wahrscheinlich, Ihnen zu sagen, „Oh, das passieren könnte, weil ich diese nicht verwandten Schaltfläche geklickt, während ich darauf wartete, um es zu retten“.

Verwenden Sie die Backgroundworker-Komponente Batch-Verarbeitung in einem separaten Thread ausführen kann, dann wird dies nicht auf dem UI-Thread auswirken.

Ich mag neu zu formulieren, was meine früheren commen bemerkt: bitte vermeiden DoEvents (), wann immer möglich, da dies fast immer eine Form von „Hack“ und verursacht Wartung Alpträume

.

Wenn Sie gehen, um die Background Straße (was ich vorschlagen), werden Sie mit Cross-Threading-Anrufe an die UI zu tun haben, wenn Sie irgendwelche Methoden oder Eigenschaften von Steuerelementen nennen wollen, da diese faden affin sind und sein müssen nur aus dem Thread rief sie erstellt wurden. Verwenden Sie Control.Invoke () und / oder Control.BeginInvoke () als angemessen.

Wenn Sie in einem Hintergrund / Worker-Thread ausgeführt werden, Sie Control.Invoke auf einer Ihrer UI-Steuerelemente aufrufen können einen Delegaten in dem UI-Thread ausgeführt werden.

Control.Invoke ist synchron (Wartet, bis die Delegierten Returns). Wenn Sie warten möchten Sie verwenden .BeginInvoke() nicht nur zur Befehlswarteschlange.

Der Rückgabewert von .BeginInvoke() ermöglicht es Ihnen, zu überprüfen, ob das Verfahren beendet oder zu warten, bis es abgeschlossen.

Mit Backgroundworker, und wenn man auch durch den Umgang mit dem ProgressChanged Ereignisse des GUI-Thread versuchen, zu aktualisieren (wie für ein ProgressBar), sollten Sie auch eingestellt WorkerReportsProgress=true, oder den Faden, den Fortschritt berichtet, wird das erste Mal sterben sie ... versucht ReportProgress anrufen

eine Ausnahme ausgelöst wird, aber man kann es nicht sehen, es sei denn, Sie haben ‚wenn geworfen‘ aktiviert ist, und der Ausgang wird nur zeigen, dass der Thread beendet.

Application.DoEvents () oder möglicherweise die Charge auf einem separaten Thread ausgeführt werden?

DoEvents () war das, was ich suchte, aber ich habe auch die Background Antworten gestimmt, weil das wie eine gute Lösung sieht, dass ich einige mehr werden untersuchen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top