Laden...

kein Zugriff auf die Form während der Laufzeit

Erstellt von royal vor 14 Jahren Letzter Beitrag vor 14 Jahren 1.803 Views
R
royal Themenstarter:in
77 Beiträge seit 2006
vor 14 Jahren
kein Zugriff auf die Form während der Laufzeit

Hey Leute,

ich habe eine zusätzliche Form erstellt, die eine ProgressBar anzeigt, um mich zu informieren, wie weit er bei der Verarbeitung meiner Daten ist. Während der Anzeige kann ich aber weder das Fenster verschieben, noch kann ich den gerade erstellen "Abbrechen"-Button benutzen. Woran liegt es, dass er mir die ProgressBars richtig anzeigt, ich die Form aber ansonsten nicht verwenden kann?

danke!

D
27 Beiträge seit 2009
vor 14 Jahren

Wie sieht dein Code aus? Kann es sein, dass du die Progressbar in einer Schleife mit einem Wert füllst?
Sollte dem so sein, dann entweder Applications.DoEvent() mit rein oder einen Timer bzw. Events nutzen, ansonsten hat die Form keine Chance sich um sich selbst zu kümmern.

mfg
DiViP

S
902 Beiträge seit 2007
vor 14 Jahren

Hallo,

DoEvents ist schlecht.
Die Berechnung solltest du in einen eigenen Thread legen (nimm am besten den BackgroundWorker), und lass dich Benachrichtigen vom Thread und aktualisiere danndeine Form.

Der BackgroundWorker bietet extra Events dafür an....
BEnutze mal die Suche,

mfg
serial

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo royal,

siehe [FAQ] Warum blockiert mein GUI?

herbivore

R
royal Themenstarter:in
77 Beiträge seit 2006
vor 14 Jahren

Vielen Dank für eure Antworten!

Bisher habe ich mich ja erfolgreich vor der Thread- und der Event- Programmierung (sofern diese nicht über das Visual Studio Ereignisfenster programmiert wurde) gedrücktm aber da komme ich wohl nun nicht drum rum. Ist aber auch nicht schlecht, dann lerne ich wieder was dazu. Werde mich die Tage mal genauer darin einlesen. Vielen Dank für eure schnelle Hilfe! 😃

@DiViP: genauso siehts aus mit der Schleife!

R
royal Themenstarter:in
77 Beiträge seit 2006
vor 14 Jahren

Hey Leute, ich bin's leider nochmal, ich hab mich mittlerweile ein bisschen in Events und Threading eingelesen und bis auf die Synchronisation verstehe ich es auch ganz gut denke ich. Bevor ich zum Problem komme am besten was zum Aufbau des Programms:

Ich drücke auf nen Button, es wird ein Fenster mit 2 ProgressBars geöffnet und es wird eine doppelte Schleife (für jede ProgressBar eine Schleife (foreach List<Wert> blub in List<List<Wert>> und als 2. Schleife jeder einzelne "Wert")) gestartet in denen langwierige Operationen durchgeführt werden. Geht die Schleife eins weiter lasse ich mir die Form mit den ProgressBars per Events aktualisieren.

Vorher hat alles blockiert. Nun habe ich diese Button-Methode in einen eigenen Thread gepackt. Soweit so gut, nun blockiert meine Hauptform nicht mehr, aber die ProgressForm blockiert. Nun habe ich mir überlegt, dass ich die ProgressForm auch in einem eigenen Thread starten könnte. Dann die Bearbeitungsevents an die Form binden, die Form in Sleep.Infinite versetzen und nach dem Durchlauf aller Schleifen Interrupt und die Form schließen lassen. Scheitert irgendwie schon daran, dass ich scheinbar zu dumm bin den ParameterizedThreadStart zu benutzen. Ich übergebe einen int-Wert als object und kann diesen nicht als int casten.

Selbst wenn das klappen würde weiß ich nicht, wie ich zum Beispiel bei einem Klick auf den Abbruch-Button in der ProgressForm den Durchgang der schleifen beenden kann. Gut, ich könnte einen Event feuern, aber was für eine Methode sollte ich damit aufrufen die die Schleife beendet?

Ich bin ein wenig verwirrt wie man das alles in Einklang bringt. Mal von einer Synchronisation abgesehen, die immer 2 Berechnungen parallel laufen lässt. Aber eins nach dem andern, das kompliziertere nach dem einfachen.

Mir würde es vermutlich helfen, wenn ihr mir sagt, was ich in einzelnen Threads laufen lassen sollte und was ich dann über Events steuern sollte.

Zu der Synchronisation vllt später mehr, erstmal das zum Grundverständnis. Sorry für den langen Text und meine Unfähigkeit!

S
902 Beiträge seit 2007
vor 14 Jahren

vielleicht solltest du dir, wie schonmal erwähnt, den BackgroundWorker anschauen, der extra für diesen Fall Events anbietet: ProgressChanged....

Und zu dem Castproblem, dazu bräuchten wir wohl etwas Code...

mfg
serial

R
royal Themenstarter:in
77 Beiträge seit 2006
vor 14 Jahren

ok, dann werde ich mir den mal anschaun 😃

zum casten:

In meiner Methode mit den Schleifen:

Thread thread_progress = new Thread(new ParameterizedThreadStart(ProgressFormErstellen));
            thread_progress.Start(new object[] { werte_list.Count });

Methode, die der Thread aufruft:


        public void ProgressFormErstellen(object indice_max)
        {
            f_progress progress = new f_progress((int)indice_max);

            progress.EventAnbindung(this);

            progress.Show();

            Thread.Sleep(Timeout.Infinite);

            progress.Close();
        }

Beim Casten meckert er, dass die Umwandlung ungültig ist. f_progress erwartet einen int-Wert.

S
902 Beiträge seit 2007
vor 14 Jahren

du übergibst ein object[]?, übergebe den integer doch direkt...

mfg
serial

R
royal Themenstarter:in
77 Beiträge seit 2006
vor 14 Jahren

ja, mit der int-Übergabe klappts. Nun aber folgendes Problem.
Ich habe wie oben beschrieben die ProgressForm erstellt und sie wird auch geöffnet. nach dem Erstellen und öffnen binde ich wie die Ereignisse im Arbeitsthread an die ProgressForm:


        public void EventAnbindung(f_hauptfenster form)
        {
            form.InnereSchleifeBearbeitungStart += new InnereSchleifeBearbeitungStartHandler(InnereSchleife_start_update);
            form.InnereSchleifeBearbeitungEnde += new InnereSchleifeBearbeitungEndeHandler(InnereSchleife_ende_update);
            form.AeussereSchleifeBearbeitungStart += new AeussereSchleifeBearbeitungStartHandler(indice_start_update);
            form.AeussereSchleifeBearbeitungEnde += new AeussereSchleifeBearbeitungEndeHandler(indice_ende_update);
        }

Beginnt nun die äußere Schleife in meiner hauptform und wird dadurch AeussereSchleifeBearbeitungStart ausgelöst kommt er an dieser Stelle nicht weiter und ich bin in einem Deadlock gefangen.

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo royal,

Nun habe ich mir überlegt, ...

alles was du dir überlegt hast, ist - sorry - Mist. Alle Fenster und Controls sollen im GUI-Thread erzeugt werden, also auch die ProgressBars. Das einzige, was in den Thread gehört, ist die langlaufende Aktion. Das steht aber haargenau in der FAQ, auf die ich oben verwiesen habe. Es gibt keinen Grund von dem dort beschriebenen Vorgehen abzuweichen. Ob du einen BackgroundWorker oder einen Thread verwendest, ist Geschmackssache und ändert nichts am Grundprinzip.

herbivore

R
royal Themenstarter:in
77 Beiträge seit 2006
vor 14 Jahren

Ok, ich weiß zwar nicht, warum, aber den Teil habe ich wohl überlesen -.-

Wie dem auch sei, ich erstelle die ProgressForm nun im GUI-Thread, genauer gesagt beim Click auf den Button. Daraufhin binde ich die Bearbeitungsereignisse an die GUI und lasse Methoden zur Aktualisierung in der ProgressForm ablaufen. Nun zeigt er mir den Progress immerhin wieder richtig an und die Hauptform blockiert auch nicht, aber dafür blockiert die ProgressForm. Das verstehe ich nun nicht. Darüber hinaus schließt er die ProgressForm nach Ablauf der Schleifen, aber da ich kein Close() aufrufe dachte ich, dass sie offen bleiben müsste.

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo royal,

ie Hauptform blockiert auch nicht, aber dafür blockiert die ProgressForm.

da alle Fenster, die in ein und demselben Thread laufen, alle zusammen blockieren oder eben alle nicht, ist es wahrscheinlich, dass die beiden Fenster doch nicht im selben Thread erzeugt werden.

herbivore

R
royal Themenstarter:in
77 Beiträge seit 2006
vor 14 Jahren

        private void fbtn_update_Click(object sender, EventArgs e)
        {
            f_progress progress = new f_progress();
            f_ergebnisse ergebnisse = new f_ergebnisse();
            progress.Show();

            this.InnereSchleifeBearbeitungStart += new InnereSchleifeBearbeitungStartHandler(progress.InnereSchleife_start_update);
            this.InnereSchleifeBearbeitungEnde += new InnereSchleifeBearbeitungEndeHandler(progress.InnereSchleife_ende_update);
            this.IndiceBearbeitungStart += new AeussereSchleifeBearbeitungStartHandler(progress.AeussereSchleife_start_update);
            this.AeussereSchleifeBearbeitungEnde += new AeussereSchleifeBearbeitungEndeHandler(progress.AeussereSchleife_ende_update);
            //this.ProgressBeginn += new ProgressBeginnHandler(progress.form_anzeigen);

            Thread thread_neu = new Thread(new ThreadStart(update));
            thread_neu.Start();
        }

Ich habe nun progress.Show() hinugefügt, nun blockieren beide nicht mehr. Davor hatte ich (nun auskommentiert) das Show() über den ProgressBeginn-Event gestartet.
Offenbar wurde die Form erst durch das Show() in dem neuen Thread erstellt.

Da er nun nicht mehr blockiert kann ich den update-Button auch mehrfahch drücken, jedoch haut der mir dann, wie ich an der ProgressAnzeige sehe einiges durcheinander und führt Berechnungen mit Werten durch die gar nicht vorgesehen waren -.- Da scheint dann wohl was mit der Synchronisierung schiefzulaufen.

Vielen Dank, dass ihr so geduldig mit mir seid, immerhin blockiert nun schonmal nichts mehr 😄

R
royal Themenstarter:in
77 Beiträge seit 2006
vor 14 Jahren

Hey Leute,

ich weiß zwar nicht, ob's jemanden interessiert aber ich schreib mal trotzdem wie es weitergeht, vllt hilfts ja auch anderen Anfängern wie meinesgleichen weiter, wenn sie das lesen.

Ich hab die Update-Methode nun in eine eigene Klasse gepackt. Dadurch ist es mir gelungen, dass er mir bei mehreren parallelen Jobs nicht die ProgressBarAnzeigen durcheinanderhaut. Denke es lag vorher daran, dass die ProgressBarAktualisierungs-Events immer für die gesamte Hauptform galten und somit alle ProgressBarForms aktualisiert wurden. Nun funktioniert es jedenfalls 😃

R
royal Themenstarter:in
77 Beiträge seit 2006
vor 14 Jahren

Noch ne blöde Frage: Wie "erstelle" ich denn die Form?

durch


f_ergebnisse ergebnisse = new f_ergebnisse();

scheinbar noch nicht, okay, wahrscheinlich ist ergebnisse dann noch null.
Wenn ich aber noch nicht will, dass die Form direkt angezeigt wird, sondern erst nach dem durchlaufen der Schleifen, muss ich dann erst
ergebnisse.Show() ausführen und direkt danach ergebnisse.Hide(), oder gibt es da auch ne andere Lösung?

1.820 Beiträge seit 2005
vor 14 Jahren

Hallo!

Mit new erzeugst du eine neue Instanz der Klasse/Form, das ist schon korrekt.
Angezeigt wird die Form mit "Show" und versteckt mit "Hide". Soll die Form modal sein, verwende "ShowDialog".

Nobody is perfect. I'm sad, i'm not nobody 🙁