Laden...

Progressbar aus Backgoundworker aktualisieren, aber nur wenn die langlaufend Aktion es sagt

Erstellt von ctfwp444 vor 10 Jahren Letzter Beitrag vor 10 Jahren 836 Views
Thema geschlossen
C
ctfwp444 Themenstarter:in
6 Beiträge seit 2012
vor 10 Jahren
Progressbar aus Backgoundworker aktualisieren, aber nur wenn die langlaufend Aktion es sagt

Hallo alle,

ich habe seit kurzem folgendes (höchstwahrscheinlich ein Verständnis-) Problem. Ich konnte leider auch nirgendwo die Antwort finden, deswegen bitte ich um Hilfe. Ich versuche ein ProgessBar zu erstellen, das an sehr viele Stellen in mehreren Programmen verwendet werden soll. Ich habe keine Möglichkeit die Funktionen zu ändern, bei denen das ProgrssBar laufen soll. Es gibt im Grunde genommen nur zwei Funktionen die ich verwenden kann:

  • InitProgressBar(int maxValue)
  • UpdateProgressBar()

Ich habe versucht das mit BackgroundWorker zu lösen.


//ProgressBar-Klasse

public class MyProgressBar
{
  private ProgressBar progressBar;
  private bool lockVar = true;

  public void InitProgressBar(int maxValue)
  {
    backgroundWorker.WorkerReportsProgress = true;
    backgroundWorker.DoWork += new DoWorkEventHandler(UpdateProgressBar);
    backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(ProgressChanged);
    this.backgroundWorker.RunWorkerAsync();
  }

  public void UpdateProgressBar()
  {
    lockVar = false;
  }

  private void UpdateProgressBar(object sender, DoWorkEventArgs e)
  {
    for (int i = 0; i <= 100; i++)
    {
       while (this.lockVar)
         System.Threading.Thread.Sleep(10);

        this.lockVar = true;

        this.backgroundWorker.ReportProgress(i); 
     }
  }

  private void ProgressChanged(object sender, ProgressChangedEventArgs e)
  {
     progressBar.Value1 = e.ProgressPercentage;
  }
}

Wenn ich das jetzt debuge, funktioniert auch alles, bis auf ProgressChanged-Funktion. Diese wird nicht mehr aufgerufen. Die Zeile this.backgroundWorker.ReportProgress(i) wird getroffen, die Funktion ProgressChanged startet nicht. Nehme ich aus der UpdateProgressBar-Funktion die while-Schleife raus und setze einfach nur Sleep(10), funktioniert alles bestens. Ich habe schon versucht anstatt mit der lock-Variable, mit einem AutoResetEvent und dem ManualResetEvent das Problem zu lösen. Damit hat es auch wegen dem selben Problem nicht geklappt. Ich hoffe ich habe mich verständlich ausgedrückt und mir kann jemand helfen. Bin für jede Hilfe dankbar.

MFG

B
357 Beiträge seit 2010
vor 10 Jahren

Du rufst nie UpdateProgressBar() auf und setzt die Variable nie auf false. Generell ist mir der Sinn dieser Lock-Variable nicht ganz schlüssig. Kannst du da noch ein paar Sätze mehr dazu sagen?

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo ctfwp444,

klingt nach [FAQ] Warum blockiert mein GUI?, Abschnitt "Achtung: Noch eine Falle". Ist aber schwer zu sagen, weil der Code, der deine Methoden aufruft, nicht zu sehen ist. Generell ist es so, dass wenn du dich an alles in der FAQ Gesagte hältst, es auch funktionieren sollte.

herbivore

C
ctfwp444 Themenstarter:in
6 Beiträge seit 2012
vor 10 Jahren

Danke für die schnelle Antwort.

Diese Klasse wird einfach von einer anderen Klasse aufgerufen die z.B. so aussieht.



class BeispielKlasse
{
  ...
  ...
  ...

  void langerProzessFunktion()
  {
    ...
    myProgressBar.InitProgressBar(397);
    ...
    for (...)    //sehr lange dauernder Prozess
    {
      ...
      myProgressBar.UpdateProgressBar();
      ...
    }

     ...
  }
}


Wenn ich die DoWork folgendermaßen gestalte, funktioniert alles:


private void UpdateProgressBar(object sender, DoWorkEventArgs e)
   {
     for (int i = 0; i <= 100; i++)
     {
         System.Threading.Thread.Sleep(10);

         this.backgroundWorker.ReportProgress(i);
      }
   }

Es macht aber wenig Sinn einfach 10ms zu warten um 1% zu erhöhen. Ich weiß ja nicht wie lange das Prozess dauern wird. Deswegen benutze ich in diesem Beispiel eine Lock-Variable die ich so lange Blockiere, bis die "Lange"-Funktion ein Signal gibt, um zu erhöhen.

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo ctfwp444,

warum so kompliziert? Wirkt für mich von hinten durch die Brust ins Auge. Und Busy Waiting sowieso ist nie schön und meistens unnötig. Lass das GUI einfach den Event der langen Aktion abonnieren und erhöhe darin den Progressbar. Beachte [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke). ReportProgress ist ja schön und gut, aber wenn es mehr Aufwand ist, es zu verwenden, als den direkten Weg zu gegen, dann sollte man es lassen.

herbivore

C
ctfwp444 Themenstarter:in
6 Beiträge seit 2012
vor 10 Jahren

Das ist es ja. Meiner Meinung nach, habe ich an alles gedacht. Aber da es nicht funktioniert, muss irgendwas falsch sein. Selber konnte ich es leider auch nach 2 Tagen Suche nicht rauskriegen.

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo ctfwp444,

natürlich kann es manchmal sein, dass man den Wald vor lauter Bäumen nicht sieht. Aber die FAQ ist erwiesenermaßen gut und deckt auch alle Spezial- und Sonderfälle ab. Damit solltest du weiterkommen.

Wenn etwas nicht geht, was eigentlich gehen sollte, hilft im Zweifel [Tutorial] Vertrackte Fehler durch Vergleich von echtem Projekt mit minimalem Testprojekt finden.

Davon abgesehen habe ich einen konkreten Hinweis gegeben, wie du die Busy Waiting Konstruktion vermeiden kann. Siehe dazu noch [FAQ] Eigenen Event definieren.

herbivore

PS: langerProzessFunktion muss natürlich auch in einem BackgroundWorker laufen, auf jeden Fall asynchron zum GUI.

Thema geschlossen