C# Async Prgoressbar in WPF

Früher gab es mal BackgroundWorker für sowas, wenn es nicht gleich ein Thread sein soll, ohne mich da jetzt zu sehr damit beschäftigt zu haben...
was du schreibst klingt aber, als hättest du das Konzept von Threads aber noch nicht wirklich verstanden. Hast du aus deinem Thread aus dem April nichts gelernt?
 
Haha ^^
Ja, mit dem BackgroundWorker hab ich mich noch nicht wirklich auseinadner gesetzt. Probiere es jetzt seit gestern irgendwie so zu lösen mit Task, async und wait aber es gelingt mir nicht.
Und ne, hab das mit die Threads noch immer nicht verstanden :(
 
DeepComputer schrieb:
Task, async und wait
Kann man an sich zwar machen, blockiert dann aber meines Wissens einen Thread im Pool, der für die Abarbeitung für async Tasks zuständig ist. Daher in diesem Fall lieber einen eigenen Thread oder BackgroundWorker (Abstraktion über Threads).

Wenn du Wait() nutzt, blockierst du den aufrufenden Thread, womit du nichts gewonnen hast.
 
DeepComputer schrieb:
Haha ^^
Ja, mit dem BackgroundWorker hab ich mich noch nicht wirklich auseinadner gesetzt. Probiere es jetzt seit gestern irgendwie so zu lösen mit Task, async und wait aber es gelingt mir nicht.

Du musst einfach deine "Harte Arbeit" aus dem Button-Event rausnehmen und als awaitable Task ausführen. Dann blockiert dein UI nicht.

Code:
private async void button1_Click(object sender, EventArgs e)
        {
            long result = await DoHardWork();
            label1.Text = result.ToString();
        }

        private Task<long> DoHardWork()
        {
            return Task.Run(() =>
            {
                long result=0;
                for (int i = 0; i < 4000000; i++) {
                    for (int j = 0; j < 4000000; j++)
                    {
                        result++;
                    }
                }
                return result;
            });
        }

Ist jetzt kein XAML WPF Gedöns, aber vielleicht kommt die Idee trotzdem rüber.
 
Also sinnvoll wäre es halt, die Arbeit nicht in dem Thread zu machen, der für die UI zuständig ist. Das machst du aber gerade. Und Arbeit blockiert halt den eigenen Thread immer. So lange die Arbeit also im Event-Listener stattfindet, so lange wird auch die UI während der Arbeit blockiert werden.

Der Wunsch, dass am Ende des Event-Listeners für den Button die Arbeit fertig ist, ist halt konzeptionell falsch. Der Event-Listener muss verlassen werden, noch während die Arbeit läuft. Und erst wenn die Arbeit fertig ist, solltest du das machen, was du gerade am Ende des Listeners machst - egal ob es manuell abgebrochen wurde oder die Arbeit fertig ist.

Wobei ich mit async/await nicht so tief drin bin, mache wenig C#, kann sein, dass es da auch geht, ohne die Abschlussarbeiten aus dem Listener zu nehmen. Aber ich stelle mir halt vor, dass dein Programm eigentlich weiterlaufen soll, und du die Arbeit als Benutzer auch abbrechen können sollst - dann wäre halt etwas wie eni BackgroundWorker durchaus sinnvoll. Der halt, wie schon gesagt, eine Abstraktion eines Threads ist. Und an Abstraktionen sollte man sich gewöhnen bei der Software-Entwicklung. (In dem Punkt, dass es abbrechbar sein soll, da irre ich mich wohl, würde ich aber drüber nachdenken)

Edit: Huch, da hat doch jemand zeitgleich quasi dasselbe geschrieben...
 
  • Gefällt mir
Reaktionen: sandreas
Schon lange her das ich WPF gemacht habe. (und ich bin froh drum :-))
Aber zu deinem Problem.
Wenn du bei WPF irgendwohin kommen willst dann darfst du im Code nicht auf dein UI zugreifen.
Arbeite mit Eigenschaften und Models (MVVM) die du im Code anpasst und die Oberfläche reagiert über Bindings oder Trigger darauf.
 
korbenm schrieb:
Wenn du bei WPF irgendwohin kommen willst dann darfst du im Code nicht auf dein UI zugreifen.
Arbeite mit Eigenschaften und Models (MVVM) die du im Code anpasst und die Oberfläche reagiert über Bindings oder Trigger darauf.
So lange er diese Sachen im Event-Listeners des Buttons macht, so würde ich einfach mal behaupten, blockiert die UI, auch wenn er mit Models und Bindings arbeitet. An einem eigenen Thread in irgendeiner Form führt halt kaum was vorbei hier.
 
@tollertyp
Jo, das hab ich auch so probiert. Irgendwas hat ihm wieder nicht gepasst gehabt.
Ich probiers morgen nochmal. Das gibts ja nicht, dass ich es nicht hinkriege.
 
Also probiert mit "Arbeit wurde nicht im Event-Listener durchgeführt"? Und ich meine jetzt nicht durch das Rausziehen des Codes in eine einfache private Methode.

Die Arbeit blockiert. Und aus meiner Sicht, so lange der Event-Listener nicht verlassen wurde, blockiert auch die UI. Es ist egal, "wo" im Event-Listener die Blockade ist.
 
Ja, hatte ich mal vor. Was wäre dein Vorschlag wie ich den Event-Listener verlassen kann? Dein Vorschlag macht schon irgendwie Sinn, weil ich ja auch nur wollen würde, dass nur 1 thread läuft, auch wenn ich 5 mal den button clicke.
 
Ok, den nehm ich morgen in Angriff. Nervt.
Und ja, den Thread einzeln nur 1x laufen zu lassen hätte ich auch anders realisieren können ;)
 
@DeepComputer

Was ist denn jetzt genau die Stelle im EventListener die so lange dauert dass die UI blockiert?
Die While-Schleife?

Dann versuch doch das:

Code:
private async void BtnCrackKey(object sender, RoutedEventArgs e) {
            ProgressBar.IsIndeterminate = true;
            CheckInput checkInput = SetValues;
            checkInput += CheckInputSyntax;
            checkInput += CheckInputPrime;
            foreach (CheckInput item in checkInput.GetInvocationList()) {
                if (item.Invoke()) {
                    continue;
                }
                else {
                    return;
                }
            }
            int i = 0;
            Versuche = 0;
            //exponent = 1;
            stopwatch.Start();

            //EXPONENT RESETEN und auf 1 setzen
            gmp_lib.mpz_init(exponent);
            gmp_lib.mpz_add_ui(exponent, exponent, 1);
            ProgressBar.IsIndeterminate = true;

            await Task.Run(() =>
            {
                while (gmp_lib.mpz_cmp(group, exponent) >= 0)
                {
                    Versuche++;
                    //exponent++;
                    gmp_lib.mpz_add_ui(exponent, exponent, 1);

                    gmp_lib.mpz_powm(result, basis, exponent, group);

                    if (gmp_lib.mpz_cmp(result, ExchangeKeyAlice) == 0)
                    {
                        //exponent wird größer als uint
                        gmp_lib.mpz_init_set(secretKeyAlice, exponent);
                        i++;
                    }
                    if (gmp_lib.mpz_cmp(result, ExchangeKeyBob) == 0)
                    {
                        gmp_lib.mpz_init_set(secretKeyBob, exponent);
                        i++;
                    }
                    if (i >= 2)
                    {
                        break;
                    }
                }
            });

            gmp_lib.mpz_powm(sharedSecretKeyAlice, ExchangeKeyBob, secretKeyAlice, group);
            gmp_lib.mpz_powm(sharedSecretKeyBob, ExchangeKeyAlice, secretKeyBob, group);

            stopwatch.Stop();
            ZeitAusgabe.Text = stopwatch.ElapsedMilliseconds.ToString() + " ms";
            ProgressBar.IsIndeterminate = false;
            stopwatch.Reset();

            ausgabeTopR.Text = secretKeyAlice.ToString();
            ausgabeTop1R.Text = secretKeyBob.ToString();
            ausgabeBottomR.Text = sharedSecretKeyAlice.ToString();
            ausgabeBottomR1.Text = Versuche.ToString();
            ProgressBar.IsIndeterminate = false;
        }

Wichtig ist halt dass du innerhalb des Tasks nicht auf die UI-Elemente zugreifen kannst.
Darum nimmt man bei WPF das MVVM Modell + Datenbindungen und nutzt NotifyPropertyChanged-Events um UI-Element zu aktualisieren.
 
tollertyp schrieb:
BackgroundWorker
Der Button-Listener konfiguriert und startet den.
Und wenn der fertig ist, wird das abgearbeitet, was am Ende des Event-Listeners ist...

Ist zwar ein WinForms-Beispiel, sollte aber keine Rolle spielen:
https://docs.microsoft.com/de-de/dotnet/api/system.componentmodel.backgroundworker?view=net-6.0
Aja, jetzt weiß ich wieder woran ich gescheitert bin. Ich finde das Ding in meiner toolbox nicht. Es gibt keinen
backworkworker dort und ich finde keine Registerkarte "Komponenten"
 
Hast du ein .net Core Projekt? Dann gibt es den auch nicht wohl.

Also nochmal zum Async/Await: Bin grundsätzlich schon dafür solche modernen Sprachkonstrukte zu nutzen. Probier es mal aus, ob es macht, was du willst.
Aber je nach Arbeit kann ein anderer Weg auch der bessere sein.
 
Für alle, die sich mal ernsthaft mit WPF und Multithreading / Tasks beschäftigen wollen, habe ich mal eine kleine Sammlung an Youtube-Links zusammen getragen, die ich zur Einführung rausgesucht hatte:

  • Threads:
  • WPF
    • Basics Playlist:
    • MVVM Playlist:
    • Navigation:
Ich stehe normalerweise eher auf Dokumentation und Text (außer vielleicht die offizielle von MIcrosoft ;) aber die Videos haben mir wirklich geholfen, die Grundlagen zu verinnerlichen. Besonders die ersten beiden sind die BESTEN Tutorials zu Tasks und Threads, die ich bisher gesehen habe.
 
  • Gefällt mir
Reaktionen: Phoenixwiger
Zurück
Oben