Laden...

BackgroundWorker darf WPF-Form nicht verändern

Erstellt von Kingkook vor 12 Jahren Letzter Beitrag vor 12 Jahren 2.200 Views
K
Kingkook Themenstarter:in
69 Beiträge seit 2011
vor 12 Jahren
BackgroundWorker darf WPF-Form nicht verändern

Liebe Com,

ich für meine Form ein BackgroundWorker, der meine GUI nach und nach Transparent machen soll.Dafür habe ich ihm im Konstruktor der Klasse die nötigen Events angehängt.


                taskbarWorker = new BackgroundWorker();
                taskbarWorker.DoWork += new DoWorkEventHandler(TaskbarDoWork);
                taskbarWorker.ProgressChanged += new ProgressChangedEventHandler(TaskbarChanged);
                taskbarWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(TaskbarCompleted);

Jetzt wartet die GUI darauf, von einer anderen Klasse ein Event zu erhalten.Wenn dieses Event gefeuert wird, wird der Worker gestartet.Er arbeitet sich normal durch, aber wenn er etwas an der GUI verändern soll, kommt eine InvalidOperationException.
Woran könnte das liegen?

Hier der BGW-Code:


        private void TaskbarDoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            worker.WorkerReportsProgress = true;
            for(int _opacity = 100 ; _opacity > 0 ; _opacity--)
            {
                worker.ReportProgress(_opacity);
                System.Threading.Thread.Sleep(100);
            }
            e.Result = e.Argument;
        }

        private void TaskbarChanged(object sender, ProgressChangedEventArgs e)
        {
            Logger.InfoWrite("Changed to {0}", e.ProgressPercentage);
            float newOpacity = (float)e.ProgressPercentage;
            this.volumeBar.Opacity = newOpacity;
        }

        private void TaskbarCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Logger.InfoWrite("Completed");
        }

Danke im voraus... Kooki 😃

D
500 Beiträge seit 2007
vor 12 Jahren
K
Kingkook Themenstarter:in
69 Beiträge seit 2011
vor 12 Jahren

Danke erstmal,
den Artikel habe ich vorher bereits gelesen aber folgenden Absatz so verstanden, dass es bei mir eigentlich gehen sollte.

BackgroundWorker

Statt mit extra Threads und Control.Invoke, kann man auch mit der BackgroundWorker-Klasse ungültige threadübergreifende Vorgänge vermeiden. Dazu müssen bei BackgroundWorker alle Zugriffe auf das GUI einfach aus den ProgressChanged- oder RunWorkerCompleted-EventHandlern durchgeführt werden. Wenn man sich daran hält, ist explizites Control.Invoke bei BackgroundWorker nicht erforderlich, denn die genannten EventHandler werden hinter den Kulissen automatisch per Control.BeginInvoke aufgerufen.

Alles vorausgesetzt, der BackgroundWorker wurde korrekt initialisiert, so dass er insbesondere einen passenden SynchronizationContext verwendet. Wenn der BGW unter Verwendung von VS im GUI-/Main-Thread erzeugt wurde, sollte das automatisch der Fall sein.

Meiner Meinung nach sollte es doch bei mir funzen, wenn der BGW bei Erstellung der WPF-Form initialisiert wird, und Events angehängt bekommt.Da ich die GUI-Manipulation erst im Changed Event ausführe, sollte doch alles stimmen oder?

D
500 Beiträge seit 2007
vor 12 Jahren

Hi Kingkook!

Es sollte automatisch funtionieren, wenn Du den BackgroudWorker im UI Thread erstellst. Das ist wichtig, dam der BGW bzw. der SynchronizationContext im BGW erkennt, ob zwischen den Threads "geswitcht" werden muss.

Jetzt wartet die GUI darauf, von einer anderen Klasse ein Event zu erhalten.Wenn dieses Event gefeuert wird, wird der Worker gestartet.

In welchem Thread wird der BGW initialisiert?

By the way: Du brauchst in der Methode TaskDoWork nicht immer das Property WorkerReportsProgress auf true setzen. Das genuegt initial einmal bei Erstellung des BGW.

Gruss,
DaMoe

F
10.010 Beiträge seit 2004
vor 12 Jahren

@Kingkook:
Sobald Thread.Sleep im BGW zum Einsatz kommt, ist es meist die falsche Herangehensweise.

Für diese simple Funktion mit Threading zu arbeiten ist nicht nötig.
Erstelle einen Forms.Timer und mache das dadrin.

Und die Exception bekommst du weil du nicht geschaut hast welche Wertebereiche Opacity hat.

K
Kingkook Themenstarter:in
69 Beiträge seit 2011
vor 12 Jahren

@DaMoe80

Initialisiert wird er, wenn auch das WPF-Fenster initialisiert wird, jedoch wird er wie gesagt in einer Methode gestartet, welche von einem Event aufgerufen wurde.

@FZelle

Mit einem Timer habe ich es vorher getestet, hat aber nicht funktioniert 😦
Mit dem Wertebereich kann es aber nichts zu tun haben, der wird erstens eingehalten und ausserdem funktioniert die ganze BGW Geschichte auch, wenn ich zB direkt bei der Initialisierung RunWorkerAsynch() aufrufe.Nur wenn ich diesen Startin einem Event aufrufe, kommt die Fehlermeldung...

446 Beiträge seit 2004
vor 12 Jahren

Hallo,

du könntest auch probieren das Fenster mit einer Animation langsam transparent zu machen.

Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp

F
10.010 Beiträge seit 2004
vor 12 Jahren

Mit dem Wertebereich kann es aber nichts zu tun haben, der wird erstens eingehalten

Da Opacity ein Float im bereich 0-1 ist, kann das nicht sein.

Mit einem Timer habe ich es vorher getestet, hat aber nicht funktioniert 😦

Dann hast du nicht den richtigen Timer genommen, gibt da nämlich 3 von.
Und funktioniert nicht ist keine vernünftige Fehlerbeschreibung.

.Nur wenn ich diesen Startin einem Event aufrufe, kommt die Fehlermeldung...

Dann hast Du uns verschwiegen aus was für einem Event das kommt.