Laden...

WPF / MVVM: Animation im Fortschrittsfenters läuft nicht

Erstellt von MillionsterNutzer vor 9 Jahren Letzter Beitrag vor 9 Jahren 1.515 Views
M
MillionsterNutzer Themenstarter:in
235 Beiträge seit 2005
vor 9 Jahren
WPF / MVVM: Animation im Fortschrittsfenters läuft nicht

Hallo zusammen,

ich habe für zeitintensive Operationen in meiner Anwendung ein kleines ProgressWindow dass ich immer vor der eigentlichen Operation öffne und danach wieder verschwinden lasse. Das Öffnen geschieht aus dem ViewModel heraus indem ich eine Message an mein Hauptfenster schicke. Das Schließen geschieht ebenfalls über eine Message die direkt an das ProgressWindow geht damit dieses sich selber schließt.

Das hat bisher eigentlich immer einwandfrei funktioniert weil im ProgressWindow eigentlich nur ein statisches Bild und ein einfaches 'Operation XYZ wird ausgeführt... Bitte warten Sie... ' angezeigt wurde.

Nun wurde aber gewünscht das sich da was drehen soll, damit der Benutzer nicht glaubt es wär alles abgestürtzt und hier wird es nun schwierig für mich. Ich habe also eine Animation (Storyboard) für das Bild erstellt welches dieses dreht. Auch das funktioniert noch einwandfrei wenn ich das ProgressWindow nur so zum testen anzeige, wenn aber tatsächlich im Hintergrund der UI-Thread mit der eigentlichen Arbeit beschäftigt ist dann bleibt damit auch meine Animation stehen.

Ich dachte erst kurz daran die zeitintensive Operation in einen separaten Thread zu packen, allerdings muss der Benutzer tatsächlich darauf warten, es ist also egal ob ich diese direkt im UI-Thread ausführe oder dieser dann auf die Beendigung des separaten Threads wartet.

Wenn ich das ProgressWindow in einem separten Thread ausführe komme ich scheinbar ebenfalls dem UI-Thread in die Quere:


        private void ReceiveMessage(OpenProgressWindowMessage action)
        {
            // This will show the dialog but the animation is not executed
            //Common.Controls.ProgressWindow wnd = new Common.Controls.ProgressWindow(this._openProgressWindowMessageAction.TitleText, this._openProgressWindowMessageAction.ShowProgressTextBox, this._openProgressWindowMessageAction.InitialProgressText, this._openProgressWindowMessageAction.ShowAnimatedIcon);
            //wnd.Show();

            this._openProgressWindowMessageAction = action;

            // This will cause an exception asking for an STA thread
            //Task.Factory.StartNew(() => { this.OpenProgressWindow(); });

            // This will not show anything at all
            //Thread progressWindowThread = new Thread(() => this.OpenProgressWindow());
            //progressWindowThread.SetApartmentState(ApartmentState.STA);
            //progressWindowThread.Start();

            // This will also cause an exception asking for an STA thread
            BackgroundWorker bgWorker = new BackgroundWorker();
            bgWorker.DoWork += ProgressWindow_DoWork;
            bgWorker.WorkerSupportsCancellation = false;
            bgWorker.WorkerReportsProgress = false;
            bgWorker.RunWorkerAsync();
        }

        private void ProgressWindow_DoWork(object sender, DoWorkEventArgs e)
        {
            Common.Controls.ProgressWindow wnd = new Common.Controls.ProgressWindow(this._openProgressWindowMessageAction.TitleText, this._openProgressWindowMessageAction.ShowProgressTextBox, this._openProgressWindowMessageAction.InitialProgressText, this._openProgressWindowMessageAction.ShowAnimatedIcon);
            wnd.Show();
        }

        private void OpenProgressWindow()
        {
            Common.Controls.ProgressWindow wnd = new Common.Controls.ProgressWindow(this._openProgressWindowMessageAction.TitleText, this._openProgressWindowMessageAction.ShowProgressTextBox, this._openProgressWindowMessageAction.InitialProgressText, this._openProgressWindowMessageAction.ShowAnimatedIcon);
            wnd.Show();
        }

Irgendwie komme ich grade nicht weiter... Kann mir jemand einen Tip geben was ich falsch mache?

VG

Ralf

R
228 Beiträge seit 2013
vor 9 Jahren

Ich dachte erst kurz daran die zeitintensive Operation in einen separaten Thread zu packen, allerdings muss der Benutzer tatsächlich darauf warten, es ist also egal ob ich diese direkt im UI-Thread ausführe oder dieser dann auf die Beendigung des separaten Threads wartet.
Ralf

Meiner Meinung nach sollten Zeit intensive Prozesse immer so ausgeführt werden, dass die UI nicht einfriert. Ich als Benutzer wüsste nie, ob das Programm noch läuft oder wie du selbst sagst abgestützt ist.

Falls der Fortschritt es zulässt würde ich ein Progress Property anbieten und eine Progressbar daran binden. Diese kannst du ja bei laufenden Aufgaben einblenden und danach wieder ausblenden. Am besten ebenfalls über ein Property.

Die Events halte ich nicht für die beste Idee.

Eine andere Idee wäre ein Overlay bei einer langen Aufgabe über das Fenster zu legen. Hier ebenfalls die visibility an eine VM Property binden und dann zeigst du eine kleine Animation, z.B. so etwas hier Creating Metro (Windows 8) Loading Animation Using XAML

Nachdem die Aufgabe abgearbeitet ist, lässt du das Overlay wieder verschwinden

Z
403 Beiträge seit 2007
vor 9 Jahren

Deinen Dialog musst du aus dem UI Thread erstellen und der Background worker müsste sich um die Arbeit im Hintergrund kümmern.

Selbst wenn der User darauf warten muss, darf kein Thread den UI Thread blockieren.

Du scheinst den Dialog aus dem Background Worker Thread zu starten, das wird nicht funktionieren.

M
MillionsterNutzer Themenstarter:in
235 Beiträge seit 2005
vor 9 Jahren

Hi Rioma,

oh man du hast natürlich Recht, ich konnte heute Morgen wohl noch nicht klar denken: Die Operation muss auf jeden Fall in einem Backgroundworker ausgeführt werden damit die UI nicht einfriert. Erst nachdem der Backgroundworker gestartet wurde kann ich das ProgressWindow model anzeigen. Wenn der BackgroundWorker fertig ist wird auch die Message zum Schließen des ProgressWindow verschickt und es geht weiter.
So passt das alles...

Evtl. nicht wirklich das was du gemeint hast, aber du hast mich in die richtige Richtung geschubst.

Viele Grüße

Ralf