Windows Forms-Threading und -Ereignisse – ListBox wird umgehend aktualisiert, aber in der Fortschrittsanzeige kommt es zu erheblichen Verzögerungen

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

Frage

Unser Team erstellt ein neues Rekrutierungs-Workflow-System, um ein altes zu ersetzen.Ich wurde mit der Migration der alten Daten in das neue Schema beauftragt.Ich habe mich dafür entschieden, ein kleines Windows Forms-Projekt zu erstellen, da die Schemata völlig unterschiedlich sind und reine TSQL-Skripte keine adäquate Lösung darstellen.

Die versiegelte Hauptklasse „ImportController“, die die Arbeit erledigt, deklariert das folgende Delegate-Ereignis:

public delegate void ImportProgressEventHandler(object sender, ImportProgressEventArgs e);
public static event ImportProgressEventHandler importProgressEvent;

Das Hauptfenster startet eine statische Methode in dieser Klasse mithilfe eines neuen Threads:

Thread dataProcessingThread = new Thread(new ParameterizedThreadStart(ImportController.ImportData));
dataProcessingThread.Name = "Data Importer: Data Processing Thread";
dataProcessingThread.Start(settings);

Die ImportProgressEvent-Argumente enthalten eine Zeichenfolgennachricht, einen maximalen int-Wert für den Fortschrittsbalken und einen aktuellen int-Fortschrittswert.Das Windows-Formular abonniert das Ereignis:

ImportController.importProgressEvent += new ImportController.ImportProgressEventHandler(ImportController_importProgressEvent);

Und reagiert auf das Ereignis auf diese Weise mit seinem eigenen Delegaten:

    private delegate void TaskCompletedUIDelegate(string completedTask, int currentProgress, int progressMax);

private void ImportController_importProgressEvent(object sender, ImportProgressEventArgs e)
            {
                this.Invoke(new TaskCompletedUIDelegate(this.DisplayCompletedTask), e.CompletedTask, e.CurrentProgress, e.ProgressMax);
            }

Abschließend werden der Fortschrittsbalken und die Listbox aktualisiert:

private void DisplayCompletedTask(string completedTask, int currentProgress, int progressMax)
        {
            string[] items = completedTask.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string item in items)
            {
                this.lstTasks.Items.Add(item);
            }

            if (currentProgress >= 0 && progressMax > 0 && currentProgress <= progressMax)
            {
                this.ImportProgressBar.Maximum = progressMax;
                this.ImportProgressBar.Value = currentProgress;
            }
        }

Die Sache ist, dass sich die ListBox sehr schnell zu aktualisieren scheint, aber der Fortschrittsbalken bewegt sich sowieso nie, bis der Stapel fast abgeschlossen ist ???was gibt ?

War es hilfreich?

Lösung 4

@John

Danke für die Links.

@Wille

Threadpooling bringt keinen Nutzen, da ich weiß, dass dadurch immer nur ein Thread erzeugt wird.Die Verwendung eines Threads dient lediglich dazu, eine reaktionsfähige Benutzeroberfläche zu haben, während SQL Server mit Lese- und Schreibvorgängen überhäuft wird.Es ist sicherlich kein kurzlebiger Thread.

Was Vorschlaghämmer angeht, haben Sie Recht.Aber wie sich herausstellte, lag mein Problem doch zwischen Bildschirm und Stuhl.Ich scheine einen ungewöhnlichen Datenstapel zu haben, der viel, viel mehr Fremdschlüsseldatensätze als die anderen Stapel enthält und zufällig zu Beginn des Prozesses ausgewählt wird, was bedeutet, dass der aktuelle Fortschritt gut 10 Sekunden lang nicht ++ wird.

@Alle

Vielen Dank für all eure Beiträge, das hat mich zum Nachdenken gebracht, was mich dazu gebracht hat, woanders im Code zu suchen, was zu meinem Ahaa-Moment der Demut geführt hat, in dem ich einmal mehr beweise, dass ein Fehler normalerweise menschlich ist :)

Andere Tipps

Vielleicht können Sie die BackgroundWorker-Komponente ausprobieren.Es erleichtert das Einfädeln.Beispiele hier:

Vielleicht außerhalb des Rahmens, aber manchmal ist es nützlich, etwas zu tun Application.DoEvents(); Damit die GUI-Teile auf Benutzereingaben reagieren, z. B. auf das Drücken der Schaltfläche „Abbrechen“ in einem Statusleistendialog.

Führen Sie zufällig Windows Vista aus?Bei einigen arbeitsbezogenen Anwendungen ist mir genau das Gleiche aufgefallen.Irgendwie scheint es eine Verzögerung zu geben, wenn der Fortschrittsbalken „animiert“ wird.

Sind Sie sicher, dass der UI-Thread während des gesamten Prozesses frei läuft?d.h.Es liegt nicht daran, dass man bei einem Join oder einer anderen Wartezeit blockiert ist?So sieht es für mich aus.

Der Vorschlag, BackgroundWorker zu verwenden, ist gut – auf jeden Fall besser als der Versuch, sich mit einer Menge Refresh/Update-Aufrufen aus dem Problem zu befreien.

Und BackgroundWorker verwendet einen Pool-Thread, was eine benutzerfreundlichere Vorgehensweise darstellt, als einen eigenen kurzlebigen Thread zu erstellen.

Es gibt keinen Gewinn durch Threadpooling, da ich weiß, dass es immer nur einen Thread hervorbringt.Die Verwendung eines Threads besteht nur darin, eine reaktionsschnelle Benutzeroberfläche zu haben, während SQL Server mit Lesevorgängen und Schreibvorgängen geschlagen wird.Es ist sicherlich kein kurzlebiger Thread.

OK, ich weiß das zu schätzen und freue mich, dass Sie Ihren Fehler gefunden haben, aber haben Sie sich BackgroundWorker angeschaut?Es macht ziemlich genau das, was Sie tun, aber auf standardisierte Weise (d. h.ohne eigene Delegaten) und ohne die Notwendigkeit, einen neuen Thread zu erstellen - beides sind (vielleicht kleine, aber vielleicht dennoch nützliche) Vorteile.

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